(開源講解)binance-chain 的 python-sdk 安裝與使用

1.安裝
要求 python 版本爲 3.6 以上,安裝命令很簡單,

pip install python-binance-chain
如果安裝過程中出現問題,請按照 sec256k1-py, 此處提供一種安裝 sec256k1-py 失敗的解決方案。

錯誤1:pkg-config包安裝不成功
這個錯誤是由於pkg-config缺失引起的,手動安裝這個包

錯誤2:secp256k1包安裝不成功
安裝這個包之前必須安裝好這幾個東西個,automake,pkg-config,libtool,libffi,gmp。

2.使用

2.1 生成錢包私鑰,公鑰和地址

from binance_chain.wallet import Wallet
from binance_chain.environment import BinanceEnvironment

product_env = BinanceEnvironment.get_production_env()
wallet = Wallet.create_random_wallet(env=product_env)
print(wallet.address)
print(wallet.private_key)
print(wallet.public_key)

代碼比較簡單,這裏就不再多做解釋了,下面看一下執行結果:

bnb1fx64c76dpew4pqqsrmvdg0l8xe8ud04h44yxsy
b88d4cc333e02d44a2e2426425d3ec4956e3793ef00a0d77a8c3338f127aa58d
b’\x02d\r\x84\x1f|\xd9J\x90\x85\xc7\x01P\xb8\xcc0\xca\xb2\x9d\xd3\x11?#\xec\xca\x19\\xd8@\x8d\x91\xc9q’
上面的結果依次是地址,私鑰和經過處理的公鑰,申明一下原始的公鑰不是這樣的

2.2 HttpApiClient 的使用

from binance_chain.http import HttpApiClient
from binance_chain.environment import BinanceEnvironment
testnet_env = BinanceEnvironment.get_production_env()
client = HttpApiClient(env=testnet_env)
prod_client = HttpApiClient()

account = client.get_account('bnb1acecavtwz6s4fat6540a5dz3vcq25lrsccxapp')
print(account)

account_seq = client.get_account_sequence('bnb1acecavtwz6s4fat6540a5dz3vcq25lrsccxapp')
print(account_seq)

fees = client.get_fees()
print(fees)

代碼中第一個是獲取 bnb1acecavtwz6s4fat6540a5dz3vcq25lrsccxapp的賬戶信息,第二個獲取bnb1acecavtwz6s4fat6540a5dz3vcq25lrsccxapp交易序號,第三個獲取費用。

執行結果如下:

{'account_number': 198155, 'address': 'bnb1acecavtwz6s4fat6540a5dz3vcq25lrsccxapp', 'balances': [{'free': '0.46438600', 'frozen': '0.00000000', 'locked': '0.00000000', 'symbol': 'BNB'}], 'flags': 0, 'public_key': [3, 142, 211, 241, 139, 162, 23, 200, 94, 195, 109, 117, 254, 214, 166, 254, 154, 61, 151, 18, 33, 59, 253, 59, 34, 38, 241, 210, 157, 129, 125, 240, 25], 'sequence': 19}


{'sequence': 19}


[{'msg_type': 'submit_proposal', 'fee': 500000000, 'fee_for': 1}, {'msg_type': 'deposit', 'fee': 62500, 'fee_for': 1}, {'msg_type': 'vote', 'fee': 0, 'fee_for': 3}, {'msg_type': 'create_validator', 'fee': 1000000000, 'fee_for': 1}, {'msg_type': 'remove_validator', 'fee': 100000000, 'fee_for': 1}, {'msg_type': 'dexList', 'fee': 100000000000, 'fee_for': 2}, {'msg_type': 'orderNew', 'fee': 0, 'fee_for': 3}, {'msg_type': 'orderCancel', 'fee': 0, 'fee_for': 3}, {'msg_type': 'issueMsg', 'fee': 50000000000, 'fee_for': 2}, {'msg_type': 'mintMsg', 'fee': 500000000, 'fee_for': 2}, {'msg_type': 'tokensBurn', 'fee': 50000000, 'fee_for': 1}, {'msg_type': 'tokensFreeze', 'fee': 500000, 'fee_for': 1}, {'fixed_fee_params': {'msg_type': 'send', 'fee': 37500, 'fee_for': 1}, 'multi_transfer_fee': 30000, 'lower_limit_as_multi': 2}, {'dex_fee_fields': [{'fee_name': 'ExpireFee', 'fee_value': 25000}, {'fee_name': 'ExpireFeeNative', 'fee_value': 5000}, {'fee_name': 'CancelFee', 'fee_value': 25000}, {'fee_name': 'CancelFeeNative', 'fee_value': 5000}, {'fee_name': 'FeeRate', 'fee_value': 1000}, {'fee_name': 'FeeRateNative', 'fee_value': 400}, {'fee_name': 'IOCExpireFee', 'fee_value': 10000}, {'fee_name': 'IOCExpireFeeNative', 'fee_value': 2500}]}, {'msg_type': 'timeLock', 'fee': 1000000, 'fee_for': 1}, {'msg_type': 'timeUnlock', 'fee': 1000000, 'fee_for': 1}, {'msg_type': 'timeRelock', 'fee': 1000000, 'fee_for': 1}, {'msg_type': 'setAccountFlags', 'fee': 100000000, 'fee_for': 1}]

上面這些我們不做過多的解釋,關於 BNB 錢包開發詳細情況請查看作者的另一篇文章

2.3 交易簽名的使用

from binance_chain.messages import TransferMsg, StdTxMsg, Signature
from binance_chain.wallet import Wallet

wallet = Wallet('私鑰')
wallet._account_number=198155
wallet._sequence=18
wallet._chain_id='Binance-Chain-Tigris'
transfer_msg = TransferMsg(
    wallet=wallet,
    symbol='BNB',
    amount=0.01,
    to_address='bnb1k3ekzgy2ana55s52ckj5pf02yypj6kcr6rme6f',
    memo='57891114'
)
data = transfer_msg.to_hex_data().decode()
print(data)

上面的私鑰替換成自己的就行,這是 BNB 轉賬交易簽名,這裏簡單說一下 BNB 的交易特徵,首先簽名的時候 account_number 和 sequence 一個是賬戶號一個是交易序號,BNB 交易是帶 memo, 他的交易可以一對一,一對多,多對一,多對多轉賬,BNB 交易有 Input 和 Output, 但他上層調用沒有找零的概念。

2.4 導入私鑰

from binance_chain.wallet import Wallet
from binance_chain.environment import BinanceEnvironment

testnet_env = BinanceEnvironment.get_production_env()
wallet = Wallet('私鑰', env=testnet_env)
print(wallet.address)
print(wallet.private_key)
print(wallet.public_key_hex)

代碼比較簡單,直接看執行結果

bnb1k3ekzgy2ana55s52ckj5pf02yypj6kcr6rme6f
privatekey
b'023fce18eda7b4599367b9af64771693ebdc9a2897ab63d50dd4f77586830cdd42'

2.5 獲取交易並解析交易

import binascii
from io import BytesIO
import typing
import base64
from binance_chain import messages
from binance_chain.protobuf import dex_pb2
from binance_chain.utils import segwit_addr
from binance_chain.http import HttpApiClient
from binance_chain.node_rpc.http import HttpRpcClient
from binance_chain.environment import BinanceEnvironment


def extract_send_msg_addresses(send_msg: dex_pb2.Send) -> typing.Tuple[str]:
    from_address = segwit_addr.encode('bnb', send_msg.inputs[0].address)
    to_address = segwit_addr.encode('bnb', send_msg.outputs[0].address)
    return from_address, to_address

def is_bnb_transaction(send_msg: dex_pb2.Send):
    for inp in send_msg.inputs:
        for coin in inp.coins:
            if coin.denom != 'BNB':
                return False
    for out in send_msg.outputs:
        for coin in out.coins:
            if coin.denom != 'BNB':
                return False
    return True

def parse_msg( msg_bytes: bytes) -> dex_pb2.StdTx:
    msg_type = msg_bytes[:4]
    msg_class = amino_msg_type_to_class(msg_type)
    msg_pb2 = msg_class().FromString(msg_bytes[4:])
    return msg_pb2

def amino_msg_type_to_class(msg_type: bytes):
    return {
            messages.NewOrderMsg.AMINO_MESSAGE_TYPE: dex_pb2.NewOrder,
            messages.CancelOrderMsg.AMINO_MESSAGE_TYPE: dex_pb2.CancelOrder,
            messages.FreezeMsg.AMINO_MESSAGE_TYPE: dex_pb2.TokenFreeze,
            messages.UnFreezeMsg.AMINO_MESSAGE_TYPE: dex_pb2.TokenUnfreeze,
            messages.TransferMsg.AMINO_MESSAGE_TYPE: dex_pb2.Send,
            messages.VoteMsg.AMINO_MESSAGE_TYPE: dex_pb2.Vote,
    }.get(binascii.hexlify(msg_type).upper())


def parse_stdtx(tx_bytes: bytes) -> dex_pb2.StdTx:
    varint_length = decode_bytes(tx_bytes[:2])
    msg_type = tx_bytes[2:6]
    assert varint_length == len(tx_bytes) - 2
    assert (binascii.hexlify(msg_type).decode('utf-8').lower() ==
            messages.StdTxMsg.AMINO_MESSAGE_TYPE.decode('utf-8').lower())
    stdtx_pb2 = dex_pb2.StdTx().FromString(tx_bytes[6:])
    return stdtx_pb2


def decode_bytes(buf):
    return decode_stream(BytesIO(buf))

def decode_stream(stream):
    shift = 0
    result = 0
    while True:
        i = read_one(stream)
        result |= (i & 0x7f) << shift
        shift += 7
        if not (i & 0x80):
            break
    return result

def read_one(stream):
    c = stream.read(1)
    if c == b'':
        raise EOFError("Unexpected EOF while reading bytes")
    return ord(c)


httpapiclient = HttpApiClient()
listen_addr ='https://dataseed3.ninicoin.io/'
rpc_client = HttpRpcClient(listen_addr)

h = 30060722
block = rpc_client.get_block(30060722)
txs  = block['block']['data']['txs']
print(txs)
if txs != None:
    for tx_str in txs:
        tx_bytes = base64.b64decode(tx_str)
        stdtx_pb2 = parse_stdtx(tx_bytes)

        msg = stdtx_pb2.msgs[0]
        msg_pb2 = parse_msg(msg)

        # 只支持轉賬類型,其他類型直接拋棄
        if type(msg_pb2) != dex_pb2.Send:
            continue

        # 只支持 BNB 轉賬類型, 代幣直接拋棄
        if not is_bnb_transaction(msg_pb2):
            continue

        from_address, to_address = extract_send_msg_addresses(msg_pb2)

        product_env = BinanceEnvironment.get_production_env()
        client = HttpApiClient(env=product_env)

        queried_txs = client.get_transactions(address=from_address, height=h)['tx']
        print(queried_txs)
        tx_dict = list(filter(lambda t: t['toAddr'] == to_address, queried_txs))[0]
        print(tx_dict)

這裏我們也不多解釋,如果看不懂這個代碼,請聯繫作者買視頻教程,下面是執行結果:

第一次打印

['0QHwYl3uClYWbmgbChS7ldSfPDJKi4D9MXmzzQ49BOWlARILRE9TLTEyMF9CTkIaLUJCOTVENDlGM0MzMjRBOEI4MEZEMzE3OUIzQ0QwRTNEMDRFNUE1MDEtODc5MhJxCibrWumHIQMOKyrvTAm/lmfD6MTtDOY/YOR5N6UWii88fzT7RbikOxJA8PlOxc73ShBQ0tXv6pXTomEDyYGYzXZIvNRF5G0+YxRalvnMurFpaJ3oUJoGFK5Dkcej+o/uIXy3ftG6LUzfkxjnqw8g2EQgAQ==', 'ygHwYl3uCkgqLIf6CiAKFLRzYSCK7PtKQorFpUCl6iEDLVsDEggKA0JOQhDEXhIgChTuM46xbhahVPV6pV/aNFFmAKp8cBIICgNCTkIQxF4ScAom61rphyECP84Y7ae0WZNnua9kdxaT69yaKJerY9UN1Pd1hoMM3UISQCmg1tAoOQPkktIOZ36QuZD5zTrVUbd0FYo/SW7c3NxADqeRhgO46xixNprsW+Fhzf+6/yuc8NmyuLE7gtw679MYubwNIBwaCDQ5NDA5Njgz']

第二次打印

 [{'txHash': 'FEEDE276687D8B98315711A0ACD019241C4BA5F8B6101E496F4B8A0DA52B3FD8', 'blockHeight': 30060722, 'txType': 'TRANSFER', 'timeStamp': '2019-08-26T11:53:26.752Z', 'fromAddr': 'bnb1k3ekzgy2ana55s52ckj5pf02yypj6kcr6rme6f', 'toAddr': 'bnb1acecavtwz6s4fat6540a5dz3vcq25lrsccxapp', 'value': '0.00012100', 'txAsset': 'BNB', 'txFee': '0.00037500', 'proposalId': None, 'txAge': 39626, 'orderId': None, 'code': 0, 'data': None, 'confirmBlocks': 0, 'memo': '49409683', 'source': 0, 'sequence': 28}]

{'txHash': 'FEEDE276687D8B98315711A0ACD019241C4BA5F8B6101E496F4B8A0DA52B3FD8', 'blockHeight': 30060722, 'txType': 'TRANSFER', 'timeStamp': '2019-08-26T11:53:26.752Z', 'fromAddr': 'bnb1k3ekzgy2ana55s52ckj5pf02yypj6kcr6rme6f', 'toAddr': 'bnb1acecavtwz6s4fat6540a5dz3vcq25lrsccxapp', 'value': '0.00012100', 'txAsset': 'BNB', 'txFee': '0.00037500', 'proposalId': None, 'txAge': 39626, 'orderId': None, 'code': 0, 'data': None, 'confirmBlocks': 0, 'memo': '49409683', 'source': 0, 'sequence': 28}

第二次打印的結果是解析出來的交易

本文是作者推出的 BNB 系列課程的一部分,大家如果覺能可以,可以聯繫作者買 BNB 相關的課程哦,包含 Java, Python, ,PHP, NodeJs 和 Go 等語言相關的課程,價格實惠。

詳細文章請閱讀:https://github.com/guoshijiang/blockchain-wallet/blob/master/bnbPythonSdk/README.md;github 上可以聯繫到作者哦,也可以給我留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章