關於本次課程
本次課程是由問我社區發起的微信羣直播課程,問我社區是一個知識付費平臺,幫助那些渴望學習知識而有沒有合適平臺的小夥伴
BNB 錢包開發
一.幣安主鏈介紹
Binance Chain是Binance及其社區開發的區塊鏈軟件系統。 Binance DEX指的是在Binance Chain之上開發的去中心化交易所。幣安的目標是創建一個以去中心化的方式發佈和交換數字資產的替代市場。幣安鏈的底層技術是基於目前比較火的項目 COSMOS 開發的,關於 COSMOS,在後面的課程中我們將會詳細介紹。幣安鏈網絡由去中心化節點組成,在幣安鏈上幾乎可以即時完成交易,出塊時間只需1秒。其速度高於其他區塊鏈。關於幣安鏈的介紹,這裏不多說了,網上有很多資料。
二.幣安主鏈節點搭建
1. 搭建全節點
Binance Chain的全節點是見證,它觀察到共識消息,從數據種子節點下載塊並執行業務邏輯以實現作爲驗證器節點(和其他完整節點)的一致狀態。完整節點還通過接受來自其他節點的事務,然後將它們中繼到核心Binance網絡來幫助網絡。
支持的平臺:Mac OS X, Windows 和 Linux.
系統需求,計算機硬件必須滿足以下節點要求:
- 運行最新版本的Mac OS X,Windows或Linux的臺式機或筆記本電腦硬件。
- 500 GB的可用磁盤空間,最低讀/寫速度爲100 MB / s。
- 4核CPU和8千兆字節的內存(RAM)。
- 寬帶互聯網連接,上傳/下載速度至少爲每秒1兆字節
- 完整節點必須每24小時運行至少4小時才能趕上Binance Chain更多時間會更好,連續運行您的節點以獲得最佳效果。
搭建完整節點
1.安裝 git lfs
Git大文件存儲(LFS)用Git中的文本指針替換大型文件,如音頻樣本,視頻,數據集和圖形,同時將文件內容存儲在遠程服務器(如GitHub.com或GitHub Enterprise)上。
請到這個界面去下載安裝lfs:https://git-lfs.github.com/
2.使用 lfs 下載二進制文件
git lfs clone https://github.com/binance-chain/node-binary.git
最新版本的完整節點版本的信息:
https://github.com/binance-chain/node-binary/blob/master/fullnode/Changelog.md
根據您要加入的網絡轉到目錄。
在以下命令中使用testnet或prod替換網絡變量:
cd node-binary/fullnode/{network}/{version}
3.初始 home 目錄
首先,您需要爲Binance Chain
選擇一個主文件夾$BNCHOME
(即〜/.bnbchaind
)。您可以通過以下方式設置:
將app.toml,config.toml
和genesis.json
從node-binary/fullnode/{network}/{version}/config /
放入$ BNCHOME/config
4.添加種子節點
要使整個節點起作用,它必須連接到一個或多個已知節點才能加入Binance Chain。
有幾個着名的種子節點在網絡中向新加入的完整節點提供已知節點地址。
它們已經在node-binary/fullnode/{network}/{version}/config/config.toml
文件中。
您還可以通過一個簡單的python腳本獲取種子信息(根據您使用的網絡替換域名):
import requests, json
d = requests.get('https://dex.binance.org/api/v1/peers').text # replace dex.binance.org with testnet-dex.binance.org for testnet
l = json.loads(d)
seeds = ",".join([ (seed["id"]+"@"+seed["original_listen_addr"]) for seed in l if seed["accelerated"] == False])
print (seeds)
如果您想添加種子節點,請隨時使用之前請求中返回的種子節點信息編輯$BNCHOME/config/config.yaml
的字段種子。
- 額外的配置
- 日誌:日誌文件位於
home
-啓動bnbchaind
時指定的目錄。 - 最新的日誌文件是
bnc.log
。該過程將每隔一小時創建一個新的日誌文件。 - 爲確保您有足夠的磁盤空間來保留日誌文件,我們強烈建議您通過更改
$BNCHOME/config/app.toml
中的logFileRoot
選項來更改日誌位置。 - 服務端口:
RPC
服務偵聽端口27147
,P2P
服務默認偵聽端口27146
。 - 除非完整節點必須偵聽其他端口,否則請確保在啓動完整節點之前打開這兩個端口。
- 存儲:所有狀態和塊數據將存儲在
$BNCHOME/data
下,不要刪除或編輯任何這些文件。
6.啓動節點
根據平臺啓動整個節點。在以下命令中用mac windows或linux替換platform變量:
./{{platform}}/bnbchaind start --home $BNCHOME --pruning breathe &
只有在趕上Binance Chain之後,整個節點才能正確處理請求。
7.同步數據
您可以通過兩種方式與區塊鏈網絡中的其他對等方同步:快速同步狀態同步。
這兩種方法可以一起使用。
快速同步數據:
- 與其他數據種子節點同步的默認方式是快速同步。
- 在快速同步中,您需要從同級中下載所有塊並在每個塊中執行所有事務。
- 同步速度約爲20塊/秒,比狀態同步慢。
配置位於$BNCHOME/config/config.toml
中:
fast_sync必須設置true
state_sync_reactor 可以設置爲 false或者true
state_sync 可以設置爲 false或者true
狀態同步:
狀態同步將使整個節點的應用程序狀態保持最新而不下載所有塊。同步速度比快速同步快。但是,您需要爲整個節點分配超過16 GB的內存才能使此功能正常工作。
配置位於 $BNCHOME/config/config.toml
中:
state_sync_reactor必須設置爲true
state_sync 必須設置爲true
recv_rate必須設置到102428800
ping_interval 建議設置到10m30s
pong_timeout建議設置到450s
狀態同步可以在短時間內幫助fullnode與其他對等體處於相同狀態(根據我們的測試,binance鏈testnet中的一個月~800M數據庫快照可以在大約45分鐘內同步),以便您可以接收最新的塊/事務和查詢 訂單簿,帳戶餘額等的最新狀態。但狀態同步不會在狀態同步高度之前下載歷史塊,如果您啓動具有狀態同步的節點並且它在高度10000處同步,則您的本地數據庫將僅在高度10000之後具有塊。
如果已經啓動了完整節點,建議的方法是在啓用狀態同步之前刪除(備份後)$BNCHOME/data
目錄和$BNCHOME/config/priv_validator_key.json
。
8.監控同步過程
您可以多次驗證curl localhost:27147/status
是否完成狀態同步,並查看latest_block_height
是否響應增加。
"sync_info": {
...
"latest_block_height": "878092",
"latest_block_time": "2019-04-15T00:01:22.610803768Z",
...
}
如果狀態同步未成功,請在下次啓動完整節點之前重複刪除$BNCHOME/data
目錄和$BNCHOME/config/priv_validator_key.json
,以防數據不一致。
一旦狀態同步成功,稍後的全節點重啓將不再進行狀態同步(如果本地塊不連續)。
但是如果你確實想要再次進行狀態同步(不要在意上一次停止和最新狀態同步快照之間有丟失的塊)並且你想保留已經同步的塊,你可以刪除$BNCHOME/data/STATESYNC.LOCK
。
例如,您在1月1日開始您的完整節點,狀態同步在高度10000,並在一段時間後關閉它在2月10日的高度22000。
現在它的3月1日,最新的可同步塊高度爲50000,你不關心22000和50000之間的塊,你可以在啓動你的節點之前刪除$BNCHOME/data/STATESYNC.LOCK
。
然後,整個節點將從高度50000繼續狀態同步。
關閉state_sync_reactor和state_sync可以在成功狀態同步後保存內存。
8.更新全節點
在大多數情況下,請下載新的二進制文件並替換它,然後重新啓動整個節點。在特殊情況下,您可能必須爲不兼容的版本(硬分叉)執行額外的步驟。
9.監控
默認情況下,Prometheus在端口28660上啓用,端點爲/metrics
。
2.搭建輕節點
Light客戶端是一個程序,它連接到一個完整的節點,以幫助用戶以安全和分散的方式訪問Binance鏈並與之交互,而無需同步完整的區塊鏈。
輕客戶端與完整節點
- Light客戶端不存儲塊或狀態,這樣它需要更少的磁盤空間(50兆就足夠了)。
- Light客戶端不加入p2p網絡,並且在空閒時不會產生任何網絡成本。網絡開銷取決於輕客戶端同時處理多少請求。
- 輕客戶端不重放鏈的狀態,因此空閒時沒有CPU成本。 CPU成本還取決於輕客戶端同時處理的請求數量。
- Light客戶端比完整節點更快,即使它落後於核心網絡幾個月。只需幾秒鐘即可趕上核心網絡。
平臺和系統需求
平臺:
- 支持在Mac OS X,Windows和Linux上運行輕量級客戶端節點。
- 輕客戶端很快就會開源,之後您可以交叉編譯輕客戶端二進制文件並在其他平臺上運行它。
要求:
- 50兆字節的可用磁盤空間。
- 2個CPU核心,50兆字節的內存(RAM)。
運行一個輕客戶端
1.下載節點
git clone https://github.com/binance-chain/node-binary.git
根據您要加入的網絡轉到目錄。在以下命令中使用testnet或prod替換網絡變量:
cd node-binary/lightd/{network}/{version}
幫助信息
./lightd --help
This node will run a secure proxy to a binance rpc server.
All calls that can be tracked back to a block header by a proof
will be verified before passing them back to the caller. Other that
that it will present the same interface as a full binance node,
just with added trust and running locally.
Usage:
lite [flags]
Flags:
--cache-size int Specify the memory trust store cache size (default 10)
--chain-id string Specify the binance chain ID (default "bnbchain")
-h, --help help for lite
--home-dir string Specify the home directory (default ".binance-lite")
--laddr string Serve the proxy on the given address (default "tcp://localhost:27147")
--max-open-connections int Maximum number of simultaneous connections (including WebSocket). (default 900)
--node string Connect to a binance node at this address (default "tcp://localhost:27147")
您可以指定上面的所有參數。
根據平臺啓動輕客戶端節點。 在以下命令中用mac,windows或linux替換platform變量:
./{{platform}}/lightd --chain-id "{chain-id}" --node tcp://{full node addr}:80 > node.log &
- 啓動輕客戶端節點有兩個必需參數:chain id和full node addr。
- 要加入的網絡的鏈ID。
- 您可以在測試網絡中的genesis文件或prod網絡中的genesis文件中找到鏈ID。
- 完整節點地址字段可以是您已部署的任何完整節點的地址。
- 您可以參考運行Binance Chain完整節點以獲取更多詳細信息。
我們提供了一堆完整的節點,您可以連接到mainnet和testnet。你可以通過一個簡單的python腳本獲取完整的節點信息(根據不同的網絡注意替換域):
import requests, json
d = requests.get('https://dex.binance.org/api/v1/peers').text # replace dex.binance.org with testnet-dex.binance.org for testnet
l = json.loads(d)
seeds = ",".join([ (seed["id"]+"@"+seed["original_listen_addr"]) for seed in l if seed["accelerated"] == False])
print (seeds)
主網示例:
./lightd --chain-id "Binance-Chain-Tigris" --node tcp://dataseed1.binance.org:80 > node.log &
測試網示例:
./lightd --chain-id "Binance-Chain-Nile" --node tcp://data-seed-pre-0-s1.binance.org:80 > node.log &
三.幣安 go-sdk詳細介紹
go-sdk是幣安開源的可以和幣安節點通信的代碼庫,除了創建和提交不同的事務外,Binance Chain GO SDK還爲BNC Chain API提供了一個瘦包裝,用於只讀端點。 它包括以下核心組件:
- 客戶端-Binance Chain事務類型和查詢的實現,例如傳輸和交易。
- 通用-核心加密函數,uuid函數和其他有用的函數。
- e2e-go-sdk開發人員的端到端測試包。對於普通用戶,它也是使用go-sdk的一個很好的參考。
- 密鑰-實施KeyManage來管理私鑰和帳戶。
- types-Binance Chain的核心類型,例如coin,account,tx和msg。
1.安裝
要求:go 11 以上版本
推薦使用 go mod
添加 github.com/binance-chain/go-sdk
到 go mod 文件
require (
github.com/binance-chain/go-sdk latest
)
replace github.com/tendermint/go-amino => github.com/binance-chain/bnc-go-amino v0.14.1-binance.1
2.go-sdk 的使用
Keymanager
在開始使用API之前,您應該構建一個密鑰管理器來幫助簽署事務消息或驗證簽名。 密鑰管理器是一個身份管理器,用於定義您在bnbchain中的身份。 它提供以下接口:
type KeyManager interface {
Sign(tx.StdSignMsg) ([]byte, error)
GetPrivKey() crypto.PrivKey
GetAddr() txmsg.AccAddress
ExportAsMnemonic() (string, error)
ExportAsPrivateKey() (string, error)
ExportAsKeyStore(password string) (*EncryptedKeyJSON, error)
}
四個構造函數來生成密鑰管理器:
NewKeyManager() (KeyManager, error)
NewMnemonicKeyManager(mnemonic string) (KeyManager, error)
NewKeyStoreKeyManager(file string, auth string) (KeyManager, error)
NewPrivateKeyManager(priKey string) (KeyManager, error)
NewLedgerKeyManager(path ledger.DerivationPath) (KeyManager, error)
- NewKeyManager。您將獲得一個新的私鑰而不提供任何東西,您可以導出並保存此KeyManager。
- NewMnemonicKeyManager。你應該提供你的助記符,通常是一個24字的字符串。
- NewKeyStoreKeyManager。您應該提供密鑰庫json文件和密碼,您可以在創建錢包帳戶時下載密鑰庫json文件。
- NewPrivateKeyManager。您應該提供私鑰的十六進制編碼字符串。
- NewLedgerKeyManager。您必須擁有帶有binance分類帳應用程序的分類帳設備並將其連接到您的機器。
示例代碼:
通過助記詞:
mnemonic := "lock globe panda armed mandate fabric couple dove climb step stove price recall decrease fire sail ring media enhance excite deny valid ceiling arm"
keyManager, _ := keys.NewMnemonicKeyManager(mnemonic)
通過keystore文件:
file := "testkeystore.json"
keyManager, err := NewKeyStoreKeyManager(file, "your password")
通過私鑰產生:
priv := "9579fff0cab07a4379e845a890105004ba4c8276f8ad9d22082b2acbf02d884b"
keyManager, err := NewPrivateKeyManager(priv)
通過 ledger 設備:
bip44Params := keys.NewBinanceBIP44Params(0, 0)
keyManager, err := NewLedgerKeyManager(bip44Params.DerivationPath())
我們爲持久的密鑰管理器提供了三個導出功能:
ExportAsMnemonic() (string, error)
ExportAsPrivateKey() (string, error)
ExportAsKeyStore(password string) (*EncryptedKeyJSON, error)
示例代碼:
km, _ := NewKeyManager()
encryPlain1, _ := km.GetPrivKey().Sign([]byte("test plain"))
keyJSONV1, err := km.ExportAsKeyStore("testpassword")
bz, _ := json.Marshal(keyJSONV1)
ioutil.WriteFile("TestGenerateKeyStoreNoError.json", bz, 0660)
newkm, _ := NewKeyStoreKeyManager("TestGenerateKeyStoreNoError.json", "testpassword")
encryPlain2, _ := newkm.GetPrivKey().Sign([]byte("test plain"))
assert.True(t, bytes.Equal(encryPlain1, encryPlain2))
對於 Ledger 密鑰,它無法導出。 因爲它的私鑰保存在 Ledger 設備上,沒有人可以直接在外面訪問它。
初始化客戶端
import sdk "github.com/binance-chain/go-sdk/client"
mnemonic := "lock globe panda armed mandate fabric couple dove climb step stove price recall decrease fire sail ring media enhance excite deny valid ceiling arm"
//----- Init KeyManager -------------
keyManager, _ := keys.NewMnemonicKeyManager(mnemonic)
//----- Init sdk -------------
client, err := sdk.NewDexClient("testnet-dex.binance.org", types.TestNetwork, keyManager)
對於sdk init,你應該知api地址。 此外,您應該知道api網關所處的網絡類型,測試網絡和生產網絡有不同的配置。
測試網絡:testnet-dex.binance.org
生產網絡:dex.binance.org
如果您想廣播某些交易,例如發送硬幣,創建訂單或取消訂單,您應該構建一個密鑰管理器。
創建一個購買訂單示例:
createOrderResult, err := client.CreateOrder(tradeSymbol, nativeSymbol, txmsg.OrderSide.BUY, 100000000, 100000000, true)
RPC 客戶端
RPC端點可用於直接通過HTTP或websockets與節點交互。 使用RPC,您可以執行低級操作,例如執行ABCI查詢,查看網絡/一致狀態或針對完整節點或輕客戶端廣播事務。
示例代碼:
nodeAddr := "tcp://127.0.0.1:27147"
testClientInstance := rpc.NewRPCClient(nodeAddr,types.TestNetwork)
status, err := c.Status()
3.go-sdk的 API
API
對於讀取選項,每個API都需要一個Query參數。 每個Query參數我們提供一個構造函數:NewXXXQuery。 我們建議您在新建Query參數時使用此構造函數,因爲構造只需要必需的參數,對於可選參數,您可以使用WithXXX來添加它。
您應該注意到一個最重要的一點,我們使用int64來表示小數。 小數長度固定爲8,表示:100000000等於1 150000000等於1.5 1050000000等於10.5
對於常見事務,響應是:
TxCommitResult
Ok bool,如果交易被鏈接受。
Log string,事務的錯誤消息。
Hash String
Code int32,結果代碼。零代表罰款。
Data string,不同類型的事務返回不同的數據消息。
四.幣安主鏈錢包開發
1.地址與私鑰生成
以下是 go-sdk 生成地址和私鑰的代碼
package main
import (
"fmt"
"github.com/binance-chain/go-sdk/keys"
)
func main() {
mnemonic := "bottom quick strong ranch section decide pepper broken oven demand coin run jacket curious business achieve mule bamboo remain vote kid rigid bench rubber"
keyManger, _ := keys.NewMnemonicKeyManager(mnemonic)
fmt.Println("Address", keyManger.GetAddr())
priKey, _ := keyManger.ExportAsPrivateKey()
fmt.Println("privateKey",priKey)
fmt.Println("=========keystore=========")
aa, _ := keyManger.ExportAsKeyStore("111111")
fmt.Println("keystore ===", aa)
fmt.Println("=========keystore=========")
}
2.充值
下面是使用 go-sdk 分析區塊的代碼:
package main
import (
"encoding/json"
"fmt"
"github.com/binance-chain/go-sdk/client/rpc"
ctypes "github.com/binance-chain/go-sdk/common/types"
"github.com/binance-chain/go-sdk/types"
"github.com/binance-chain/go-sdk/types/tx"
)
func main() {
nodeAddr := "tcp://127.0.0.1:27147"
client := rpc.NewRPCClient(nodeAddr, ctypes.ProdNetwork)
codec := types.NewCodec()
number := int64(8095579)
//number := int64(8643229)
res, _ := client.Block(&number)
txs := res.Block.Data.Txs
parsedTxs := make([]tx.StdTx, len(txs))
for i := range txs {
err := codec.UnmarshalBinaryLengthPrefixed(txs[i], &parsedTxs[i])
if err != nil {
fmt.Println("Error - codec unmarshal")
return
}
}
bz, err := json.Marshal(parsedTxs)
if err != nil {
fmt.Println("Error - json marshal")
return
}
fmt.Println(string(bz))
}
3.提現
提下主要就是簽名和轉賬,使用下面代碼:
package transaction
import (
"fmt"
"time"
"github.com/binance-chain/go-sdk/client/basic"
"github.com/binance-chain/go-sdk/client/query"
"github.com/binance-chain/go-sdk/common/types"
"github.com/binance-chain/go-sdk/keys"
"github.com/binance-chain/go-sdk/types/msg"
"github.com/binance-chain/go-sdk/types/tx"
)
type TransactionClient interface {
CreateOrder(baseAssetSymbol, quoteAssetSymbol string, op int8, price, quantity int64, sync bool, options ...Option) (*CreateOrderResult, error)
CancelOrder(baseAssetSymbol, quoteAssetSymbol, refId string, sync bool, options ...Option) (*CancelOrderResult, error)
BurnToken(symbol string, amount int64, sync bool, options ...Option) (*BurnTokenResult, error)
ListPair(proposalId int64, baseAssetSymbol string, quoteAssetSymbol string, initPrice int64, sync bool, options ...Option) (*ListPairResult, error)
FreezeToken(symbol string, amount int64, sync bool, options ...Option) (*FreezeTokenResult, error)
UnfreezeToken(symbol string, amount int64, sync bool, options ...Option) (*UnfreezeTokenResult, error)
IssueToken(name, symbol string, supply int64, sync bool, mintable bool, options ...Option) (*IssueTokenResult, error)
SendToken(transfers []msg.Transfer, sync bool, options ...Option) (*SendTokenResult, error)
MintToken(symbol string, amount int64, sync bool, options ...Option) (*MintTokenResult, error)
TimeLock(description string, amount types.Coins, lockTime int64, sync bool, options ...Option) (*TimeLockResult, error)
TimeUnLock(id int64, sync bool, options ...Option) (*TimeUnLockResult, error)
TimeReLock(id int64, description string, amount types.Coins, lockTime int64, sync bool, options ...Option) (*TimeReLockResult, error)
SetAccountFlags(flags uint64, sync bool, options ...Option) (*SetAccountFlagsResult, error)
AddAccountFlags(flagOptions []types.FlagOption, sync bool, options ...Option) (*SetAccountFlagsResult, error)
SubmitListPairProposal(title string, param msg.ListTradingPairParams, initialDeposit int64, votingPeriod time.Duration, sync bool, options ...Option) (*SubmitProposalResult, error)
SubmitProposal(title string, description string, proposalType msg.ProposalKind, initialDeposit int64, votingPeriod time.Duration, sync bool, options ...Option) (*SubmitProposalResult, error)
DepositProposal(proposalID int64, amount int64, sync bool, options ...Option) (*DepositProposalResult, error)
VoteProposal(proposalID int64, option msg.VoteOption, sync bool, options ...Option) (*VoteProposalResult, error)
GetKeyManager() keys.KeyManager
}
type client struct {
basicClient basic.BasicClient
queryClient query.QueryClient
keyManager keys.KeyManager
chainId string
}
func NewClient(chainId string, keyManager keys.KeyManager, queryClient query.QueryClient, basicClient basic.BasicClient) TransactionClient {
return &client{basicClient, queryClient, keyManager, chainId}
}
func (c *client) GetKeyManager() keys.KeyManager {
return c.keyManager
}
type Option func(*tx.StdSignMsg) *tx.StdSignMsg
func WithSource(source int64) Option {
return func(txMsg *tx.StdSignMsg) *tx.StdSignMsg {
txMsg.Source = source
return txMsg
}
}
func WithMemo(memo string) Option {
return func(txMsg *tx.StdSignMsg) *tx.StdSignMsg {
txMsg.Memo = memo
return txMsg
}
}
func WithAcNumAndSequence(accountNum, seq int64) Option {
return func(txMsg *tx.StdSignMsg) *tx.StdSignMsg {
txMsg.Sequence = seq
txMsg.AccountNumber = accountNum
return txMsg
}
}
func (c *client) broadcastMsg(m msg.Msg, sync bool, options ...Option) (*tx.TxCommitResult, error) {
// prepare message to sign
signMsg := &tx.StdSignMsg{
ChainID: c.chainId,
AccountNumber: -1,
Sequence: -1,
Memo: "",
Msgs: []msg.Msg{m},
Source: tx.Source,
}
for _, op := range options {
signMsg = op(signMsg)
}
if signMsg.Sequence == -1 || signMsg.AccountNumber == -1 {
fromAddr := c.keyManager.GetAddr()
acc, err := c.queryClient.GetAccount(fromAddr.String())
if err != nil {
return nil, err
}
signMsg.Sequence = acc.Sequence
signMsg.AccountNumber = acc.Number
}
// special logic for createOrder, to save account query
if orderMsg, ok := m.(msg.CreateOrderMsg); ok {
orderMsg.ID = msg.GenerateOrderID(signMsg.Sequence+1, c.keyManager.GetAddr())
signMsg.Msgs[0] = orderMsg
}
for _, m := range signMsg.Msgs {
if err := m.ValidateBasic(); err != nil {
return nil, err
}
}
// Hex encoded signed transaction, ready to be posted to BncChain API
hexTx, err := c.keyManager.Sign(*signMsg)
if err != nil {
return nil, err
}
param := map[string]string{}
if sync {
param["sync"] = "true"
}
commits, err := c.basicClient.PostTx(hexTx, param)
if err != nil {
return nil, err
}
if len(commits) < 1 {
return nil, fmt.Errorf("Len of tx Commit result is less than 1 ")
}
return &commits[0], nil
}
或者:
func signAndSend() {
test1Mnemonic := "bottom quick strong ranch section decide pepper broken oven demand coin run jacket curious business achieve mule bamboo remain vote kid rigid bench rubber"
test1KeyManger, _ := keys.NewMnemonicKeyManager(test1Mnemonic)
keyManagerP1, _ := keys.NewPrivateKeyManager("091cf0dfe62c369b27be5ca5ceeecd2f80fa14d5bd04d27dc759ed6ac5f78d55")
fromAddr := test1KeyManger.GetAddr()
signMsg := []struct {
msg msg.Msg
keyManager keys.KeyManager
AccountNumber int64
sequence int64
} {
{msg.CreateSendMsg(fromAddr, ctypes.Coins{ctypes.Coin{Denom:"BNB", Amount:600000000000000000}},
[]msg.Transfer{{keyManagerP1.GetAddr(), ctypes.Coins{ctypes.Coin{ Denom:"BNB", Amount:600000000000000000}}}} ),
test1KeyManger, 27718, 1,
},
}
for _, c := range signMsg {
signMsg := tx.StdSignMsg{
ChainID: "Binance-Chain-Tigris",
AccountNumber: c.AccountNumber,
Sequence: c.sequence,
Memo: "memo",
Msgs: []msg.Msg{c.msg},
Source: 0,
}
fmt.Println("signMsg = ", signMsg)
signResult, _ := test1KeyManger.Sign(signMsg)
fmt.Println("signResult = ", signResult)
}
附 1:
幣安文檔:https://docs.binance.org
github地址:https://github.com/binance-chain
瀏覽器地址:https://explorer.binance.org/
附 2:
區塊鏈鏈錢包技術指南:https://github.com/guoshijiang/blockchain-wallet
問我社區:https://github.com/gingernet/AskMe/
區塊鏈開發:http://www.gingernet.vip/#/home