Microsoft Blockchain 合作案例

區塊鏈實作:在成功得案例上做出您的第一個應用

WiFi access:

msevent998dl

Azure Blockchain-as-a-service(Demo)-30mins

Michael Chi 軟體開發工程師

作者GitHub:https://github.com/michael-chi/blockchain-learning

Before we start

  • What is …

    • Blockchain
    • distributed ledger
    • smart contract
  • Plus

    • have programming knowledge
    • Azure Knowledge
  • 純技術 Workshop

  • 區塊鏈解決方案中遇到問題如何解決,以解決的思路

  • Blockchain Case:

    • 東南亞航空公司
    • 農業產銷的公司,類似台糖的農產品版本

農業產銷的公司

  • 有數個 farmer 管理者,用以確認 農人、農地大小、產品品質
  • 農民有數種、法律有數種、農地有數種,希望解決繁瑣的問題

解決方式

IPFS 行星檔案系統:類似區塊鏈 p2p 的分散式檔案系統

  • 將農民資訊 ID 放到 smart contract 上,而藉由 hash ID ,將個人資料儲存於資料庫,不上鏈
  • 農地資料同上,ID 上鏈,其餘放到 IPFS 上

東南亞港口管理的機構

港口想要建造一艘新的船隻,非常麻煩,可能需要 3060 張的憑證,需要 36 個月,而其中多數憑證需要人工申請,非常耗時耗人力。

解決方式

一家船隻的擁有者,造船時,創建一個 smart contract 放到區塊鏈上,每張 smart contract 都代表一個憑證,取得憑證後,交給監管驗證,核發後建造。

Baseline

  • 參與者多
  • 資料共享者多
  • 憑證可以透過區塊鏈在多個機構中流通

參與者越多,越適合用區塊鏈來解決問題

How we work with the customer

  • 3 週聯絡交流
  • 2 週前往顧客公司討論
  • 2 月 coding

航空公司

希望多家航空公司的里程數(紅利)可以共用,多個參與者可以擁有共通的交流平台。

  • 擁有一個共通的貨幣,用以交換產品或價值
  • 一個開放的平台,任何人只要他想,就可以來參與這個平台
  • 這個平台必須夠安全
  • 必須是全球性的
  • 輕易的加入這個聯盟

解決方式

我們認為區塊鏈是好的解決方案、一個安全的方式,資料在其中是分享的,且是一個分散式的系統,資料就會在節點之中去 Ledger。
How do we

  • 創建一個 Token 、 ETH 、 Hyperledger?
  • 外幣交換的機制?
  • Track Transaction?
  • 如何與現有的會員系統做整合?
  • interact with other participates?
  • 如何建立一個全球可信賴的系統?
  • 多國間的資料如何同步?
  • 如何管理?

思考方向

  • 先解決簡單的問題
  • 設計一個給單一客戶的架構
  • 延伸至其他公司

業務場景

  • 創建一個貨幣,將各個公司的會員點數擁有一個共通的轉換媒介
  • 所有透過這個貨幣的交易都必須被完整的記錄下來
  • 所以的夥伴必須被管理,必須是某個航空公司的會員才能轉換

區塊鏈角度

  • 所有的客戶、智能合約都是一個 address 。
  • 需要數個 contract
    • Token contract
    • Exchange Rate Contract
    • Transaction Contract
      • 記錄一些特殊的交易邏輯

We decide to

微軟在 eth 有各種合作,又 因為有 80% 的 Token 都是 ERC 20 所以採取 ERC20

  • smart from eth
  • uses ERC 20 Standard
    • Function
      • total supply
      • balanceOf
      • Transfar
      • transferFrom
      • Approve
      • allowance
    • Events
      • Transfer
      • Approval
  • openzepplin:一個針對安全性做增強的 Token 範本

Create Digital Token

==等補簡報中的 3 個 smart contract 的 Function==

  • Transaction
  • Token
  • Echange Rate

Questions

Now we have smart contracts ready

  • Q:如果邏輯需要更改時該如何是好?
    • 如何 update ?
  • A:Proxy Pattern
    • 將邏輯與資料分開
    • 透過更改 Proxy contract ,判斷應該呼叫哪個版本
  • Q:如何使 API、操作 smart contract ,使之呈現於終端裝置上?
  • A:需要一個
    • Library
    • API
    • Authentication
      • In smart contract
      • In API
        • Truffle.js 部署 Smart Contracts 並測試
    • WEB3.JS

      Challenge

  • Q:如何管理雲端的 eth 與離線的 Database
  • A:在 Azure 上
    • Function App
    • Web App/API app
    • Vitual Machines

兩種解決方式

oracle

小結

  • 呼叫己身 API
  • 管理自己的會員
  • 以 VPN 等等網路傳到區塊鏈上同步
  • 需要報表時,從 Databasr 查詢
  • 需要驗證時,從 Blockchain 查詢

未來的問題

  • 區塊鏈、SQL 哪邊是主體
  • 是否能夠讓網路互連
  • 普通的 CI/CD 可以使用 Azure 內建的 CI/CD
  • Smart Contract CI/CD
    • 當你部署一個新的版本後,對區塊鏈來說就是一個全新的事情,而究竟要不要自動使用 CI/CD 尚未有定論。

What’s Next

  • 我們不希望每一個 case 都從頭開始
  • 我們希望能夠有個 base ,之後的開發都由此延伸
  • 我們有一個解決方案在 Azure 上,只要將它組合起來

Before Start

https://www.microsoftazurepass.com/SubmitPromoCode
https://onedrive.live.com/?authkey=%21AHCMYjJIaYWpXF0&id=E0579E51F1904020%21363386&cid=E0579E51F1904020

快速的建立區塊鏈並運用
運用 Azure 上的 template

從 60% ~ 70% 開始建立區塊鏈
之後會把代碼開源出來到 GitHub (大驚!!

For 聯盟鏈

SITCON 夏令營 2017 chatbot 共筆

一小隊 2017 SITCON 夏令營 bot 共筆

bot目的:處理日常金融用途1

@book_keeping_bot


日常記帳

  • 收/支出、時間、內容、金額、總金額
        * 記錄前次內容提供清空
    
    * 將記帳紀錄固定於單一訊息

指令:

  • /list:將目前表格秀出
         讓用戶可選擇要編輯的訊息
    
  • 輸入順序:收入(+)/支出(-) 項目 金額
         直接設定成表格填空
    
     從使用者API中提取時間
  • /start 開始說明

    book-keeping, [19.01.18 13:10]
    OK, William
    你準備好了…… 讓我們開始記帳吧

book-keeping, [19.01.18 13:10]
記帳請依序輸入 /add +/-

book-keeping, [19.01.18 13:10]
請輸入/list查看帳本,輸入/total 獲取總資產

book-keeping, [19.01.18 13:10]
借款請依序輸入 /lend <@username>

book-keeping, [19.01.18 13:10]
查看借貸請輸入 /ldict <@username>


user借還錢

  • 借貸時間、內容、金額、備註
        * 利用@表示被借錢者
    
    * 借還錢時與@確認借據正確性
     
     指令:將目前欠款人統一成一張清單
     指令:查詢目前欠款紀錄
     指令:查詢歷史借款人(username/借款次數、金額
     

借貸實際測試範例

William Mou, [19.01.18 13:10]
/lend @WilliamMou 100

book-keeping, [19.01.18 13:10]
借款給 @WilliamMou 100元

book-keeping, [19.01.18 13:10]
請借款人 @WilliamMou 回傳 /borrow @WilliamMou 1516338639 驗證

William Mou, [19.01.18 13:10]
/borrow @WilliamMou 1516338639

book-keeping, [19.01.18 13:10]
提醒:輸入 /payback @WilliamMou 1516338639 還款

William Mou, [19.01.18 13:11]
/ldict @WilliamMou

book-keeping, [19.01.18 13:11]
欠款確認,欠100元


Bot架構

      array:
          0:
              id:
              time:
              type:
              proj:
              money:
              total:
          ...

相關bot

bot:
@RawDataBot

相關網站

bot&python3
telegpot說明文件
python telegram定義
git版本控制

技術問題

  1. telegram如何輸出適合螢幕大小的記帳表格
# -*- coding: utf8 -*-

import telepot
from telepot.loop import MessageLoop
from telepot.namedtuple import (
    ReplyKeyboardMarkup, 
    KeyboardButton,
    InlineKeyboardMarkup,
    InlineKeyboardButton
)
from random import choice
import json
import time

TOKEN = ''

bot = telepot.Bot(TOKEN)
telBot=telepot.Bot (TOKEN) 
Bot_inf=telBot.getMe()

#資料結構:{chatid:[[+-,money,event],[+-,money,even],[+-,money,even]]}
moneydict={}
#資料傑{idtousername:{data:[1,]}} 0:未確認 1:確認 2:還款確認 pop:還款完成
lenddict={}

def print_msg(msg):
    print(json.dumps(msg, indent=10))

def on_chat(msg):
    print_msg(msg)
    print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
    header = telepot.glance(msg, flavor="chat",long =True)
    data=""
    if header[0] == "text":
        text = msg["text"]
        # command
        if text.startswith("/"):
            command = text.lstrip("/")
            
            if command == "start":
                text = "OK, {}\n你準備好了...... 讓我們開始記帳吧"
                bot.sendMessage(header[2], text.format(msg["from"]["first_name"]))
                bot.sendMessage(header[2], "記帳請依序輸入 /add +/- <money> <porj>")
                bot.sendMessage(header[2], "請輸入/list查看帳本,輸入/total 獲取總資產")
                bot.sendMessage(header[2], "借款請依序輸入 /lend <@username> <money> <porj>")
                bot.sendMessage(header[2], "查看借貸請輸入 /ldict <@username>")
                
            elif command[:3] == "add":
                #data=[+-,money,event]
                data=command[3:].split()
                if data[0] == '+' or data[0]=='-':
                    try:
                        int(data[1])
                        bot.sendMessage(header[2],"增加收支細項"+str(data[2]))
                        if header[2] in moneydict:
                            moneydict[header[2]].append(data)
                        else:
                            moneydict[header[2]]=[data]
                        bot.sendMessage(header[2],"收支帳本"+str(moneydict[header[2]]))
                    except:
                        bot.sendMessage(header[2],"請符合格式ouo")
                else:
                    bot.sendMessage(header[2],"請符合格式ouo")
    
            elif command[:4] == "lend":
                data=command[4:].split()
                bot.sendMessage(header[2],"借款給 "+str(data[0])+" "+str(data[1])+"元")
                if msg["from"]["username"]+"to"+str(data[0][1:]) in lenddict:
                    lenddict[str(msg["from"]["username"])+"to"+str(data[0][1:])][msg["date"]]=[0,str(data[1])]
                else:
                    lenddict[str(msg["from"]["username"])+"to"+str(data[0][1:])]={msg["date"]:[0,str(data[1])]}

                bot.sendMessage(header[2],"請借款人 "+str(data[0])+" 回傳 /borrow @"+str(msg["from"]["username"])+" "+str(msg["date"])+" 驗證")
                #bot.sendMessage(header[2],str(lenddict))

                '''
                if str(msg["from"]["username"])+"to"+str(data[0]) in lenddict:
                    lenddict[str(msg["from"]["username"])+"to"+str(data[0])]={msg[data]:0}
                    bot.sendMessage(header[2],0)
                else:
                    lenddict[str(msg["from"]["username"])+"to"+str(data[0])]={msg[data]:0}
                '''    
            #commond: /borrow @username date
            elif command[:6] == "borrow":
                data=command[6:].split()
                lenddict[data[0][1:]+"to"+msg["from"]["username"]][int(data[1])][0]=1
                #bot.sendMessage(header[2],str(lenddict))
                bot.sendMessage(header[2],"提醒:輸入 /payback " + data[0] + " " +data[1]+" 還款")
                
            #commond: /payback @username date
            elif command[:7] == "payback":
                data=command[7:].split()
                lenddict[data[0][1:]+"to"+msg["from"]["username"]][int(data[1])][0]=2
                bot.sendMessage(header[2],"請 "+data[0]+" 確認 @"+str(msg["from"]["username"])+" 是否還款,並輸入 /payok @"+msg["from"]["username"]+" "+str(data[1])+" 確認")
                
            #commond: /payok @username date
            elif command[:5] == "payok":
                data=command[5:].split()
                lenddict[msg["from"]["username"]+"to"+data[0][1:]].pop(int(data[1]))
                bot.sendMessage(header[2],"還款確認完成><資料已核銷")
                
            elif command == "list":
                for i in range(len(moneydict[header[2]])):
                    bot.sendMessage(header[2],"收支帳本"+str(moneydict[header[2]][i]))
                    
            # /ldict @username
            elif command[:5] == "ldict":
                data=command[5:].split()
                if msg["from"]["username"]+"to"+data[0][1:] in lenddict:
                #for i in lenddict[msg["from"]["username"]+"to"+data[0][1:]]:
                    for i in lenddict[msg["from"]["username"]+"to"+data[0][1:]]:
                        if lenddict[msg["from"]["username"]+"to"+data[0][1:]][i][0]==0:
                            bot.sendMessage(header[2]," 欠款待確認,欠"+str(lenddict[msg["from"]["username"]+"to"+data[0][1:]][i][1])+"元")
                        elif lenddict[msg["from"]["username"]+"to"+data[0][1:]][i][0]==1:
                            bot.sendMessage(header[2]," 欠款確認,欠"+str(lenddict[msg["from"]["username"]+"to"+data[0][1:]][i][1])+"元")
                        elif lenddict[msg["from"]["username"]+"to"+data[0][1:]][i][0]==2:
                            bot.sendMessage(header[2]," 還款待確認,欠"+str(lenddict[msg["from"]["username"]+"to"+data[0][1:]][i][1])+"元")
                else:
                    bot.sendMessage(header[2],str(data[0])+" 暫無欠您的款項")
                    
            elif command[:5] == "total":
                s=0
                for i in range(len(moneydict[msg['chat']['id']])):
                    if moneydict[msg['chat']['id']][i][0]=='+':
                        try:
                            s+=int(moneydict[msg['chat']['id']][i][1])
                        except:
                            pass
                    else:
                        try:
                            s-=int(moneydict[msg['chat']['id']][i][1])
                        except:
                            pass
                bot.sendMessage(header[2],str(msg['chat']['id'])+"總資產:"+str(s))
            
            elif command[:9] == "del_list":
                del moneydict[msg['chat']['id']]
                bot.sendMessage(header[2],"以清除您的儲蓄列表")
              


        # other msg
        #else: 
            # 我覺得不行!
            #image_url = "https://cdn.pixabay.com/photo/2016/03/22/23/45/money-1273908_960_720.jpg"
            #bot.sendPhoto(header[2], image_url)
    #bot.sendMessage(header[2],"輸入/start查看指令")
        if "@all" in msg["text"]:
            admins_list=[]
            admins_dict=telBot.getChatAdministrators (msg["chat"]["id"])
            chat_name=msg["chat"]["title"].encode('utf8')
            print(admins_dict)
            for admin in admins_dict:
                if 'username' in admin['user']:
                    admins_list.append('@'+str(admin['user']["username"])+" ")
                else:
                    user_id=admin["user"]["id"]

                    try :
                        first_name=admin["user"]["first_name"]
                    except:
                        pass
                    try :
                        last_name=admin["user"]["last_name"]
                    except:
                        pass
                    try:
                        admins_list.append('@ '+first_name+" "+last_name)
                    except:
                        try:
                            admins_list.append('@'+first_name)
                        except:
                            pass
                        try:
                            admins_list.append('@'+last_name)  
                        except:
                            pass
                print(admins_list)
            send=""
            for admin in admins_list:
                send+= admin + " "
            bot.sendMessage(header[2], send)
            print(admins_list)
        
        if "@book_keeping_bot 閉嘴" in msg["text"] or "shut up" in msg["text"]:
            bot.sendMessage(header[2], '@' + msg['from']['username'] + " 對不起Q.Q")
            time.sleep(5)
            bot.sendMessage(header[2], '@' + msg['from']['username'] + " 你以為我會這樣說ㄇ?")
            bot.sendMessage(header[2], '@' + msg['from']['username'] + "\n\
 ——————/´ ¯/) \n\
—————--/—-/   \n\
—————-/—-/   \n\
———--/´¯/'--'/´¯`·_\n\
———-/'/--/—-/—--/¨¯\n\
——--('(———- ¯~/'--')\n\
———\————-'—--/\n\
———-'\'————_-·´\n\
————\———--(\n\
————-\———-- ")
            
        elif "@book_keeping_bot" in msg["text"]:

            bot.sendMessage(header[2], '@' + msg['from']['username'] + " 我可是很忙得")
            image_url ="https://www.moedict.tw/%E5%88%B7%E5%88%B7.png"
            bot.sendMessage(header[2], '@' + msg['from']['username'] + " 找我有啥事情?")
            bot.sendMessage(header[2],"孤單寂寞覺得冷?")
            bot.sendMessage(header[2],"簡單,我可以陪你刷起來!")
            for ii in range(3):
                bot.sendPhoto(header[2], image_url)
                
        
        
MessageLoop(bot, {
    'chat': on_chat,
    #'callback_query': on_callback_query,
}).run_as_thread()

print('Listening ...')