Last active
April 26, 2020 16:11
-
-
Save zhaojun-sh/20d909743ceba2cda8a5f5cfde615a1d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // 20200426 v0.10 增加共管账户lockout审批功能 | |
| // 20200424 v0.9 增加创建共管账户和审批功能 | |
| // 20200421 v0.8 增加建组gid和获取enode签名功能 | |
| // 20200409 v0.5 更新reqDcrmAddr接口,mode参数放到data中 | |
| // 20200401 v0.4 增加lockout测试功能 | |
| // 20200327 v0.3 增加测试结果统计功能,打印出失败的交易KeyID | |
| // 20200325 v0.2 支持循环测试 | |
| // 20200324 v0.1 支持发送个人模式申请DCRM地址 | |
| // | |
| package main | |
| import ( | |
| "crypto/ecdsa" | |
| "encoding/hex" | |
| "encoding/json" | |
| "errors" | |
| "flag" | |
| "fmt" | |
| "io/ioutil" | |
| "math/big" | |
| "strconv" | |
| "strings" | |
| "time" | |
| "github.com/ethereum/go-ethereum/accounts" | |
| "github.com/ethereum/go-ethereum/accounts/keystore" | |
| "github.com/ethereum/go-ethereum/common" | |
| "github.com/ethereum/go-ethereum/core/types" | |
| "github.com/ethereum/go-ethereum/crypto" | |
| "github.com/ethereum/go-ethereum/rlp" | |
| "github.com/onrik/ethrpc" | |
| ) | |
| const ( | |
| KEYFILE = `{"version":3,"id":"16b5e31c-cd1a-4cdc-87a6-fc4164766698","address":"00c37841378920e2ba5151a5d1e074cf367586c4","crypto":{"ciphertext":"2070bf8491759f01b4f3f4d6d4b2e274f105be8dc01edd1ebce8d7d954eb64bd","cipherparams":{"iv":"03263465543e4631db50ecfc6b75a74f"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"9c7b6430552524f0bc1b47bed69e34b0595bc29af4d12e65ec966b16af9c2cf6","n":8192,"r":8,"p":1},"mac":"44d1b7106c28711b06cda116205ee741cba90ab3df0776d59c246b876ded0e97"}}` | |
| DCRM_TO_ADDR = `0x00000000000000000000000000000000000000dc` | |
| CHAIN_ID = 30400 //DCRM_walletService ID | |
| ) | |
| type response struct { | |
| Status string `json:"Status"` | |
| Tip string `json:"Tip"` | |
| Error string `json:"Error"` | |
| Data interface{} `json:"Data"` | |
| } | |
| type dataResult struct { | |
| Result string `json:"result"` | |
| } | |
| type dataEnode struct { | |
| Enode string `json:"Enode"` | |
| } | |
| type groupInfo struct { | |
| Gid string `json:"Gid"` | |
| Mode string `json:"Mode"` | |
| Count int `json:"Count"` | |
| Enodes interface{} `json:"Enodes"` | |
| } | |
| type reqAddrData struct { | |
| TxType string `json:"TxType"` | |
| GroupID string `json:"GroupId"` | |
| ThresHold string `json:"ThresHold"` | |
| Mode string `json:"Mode"` | |
| TimeStamp string `json:"TimeStamp"` | |
| Sigs string `json:"Sigs"` | |
| } | |
| type acceptData struct { | |
| TxType string `json:"TxType"` | |
| Key string `json:"Key"` | |
| Accept string `json:"Accept"` | |
| TimeStamp string `json:"TimeStamp"` | |
| } | |
| type lockoutData struct { | |
| TxType string `json:"TxType"` | |
| DcrmAddr string `json:"DcrmAddr"` | |
| DcrmTo string `json:"DcrmTo"` | |
| Value string `json:"Value"` | |
| Cointype string `json:"Cointype"` | |
| GroupID string `json:"GroupId"` | |
| ThresHold string `json:"ThresHold"` | |
| Mode string `json:"Mode"` | |
| TimeStamp string `json:"TimeStamp"` | |
| Memo string `json:"Memo"` | |
| } | |
| type reqAddrStatus struct { | |
| Status string `json:"Status"` | |
| PubKey string `json:"PubKey"` | |
| Tip string `json:"Tip"` | |
| Error string `json:"Error"` | |
| AllReply interface{} `json:"AllReply"` | |
| TimeStamp string `json:"TimeStamp"` | |
| } | |
| type lockoutStatus struct { | |
| Status string `json:"Status"` | |
| OutTxHash string `json:"OutTxHash"` | |
| Tip string `json:"Tip"` | |
| Error string `json:"Error"` | |
| AllReply interface{} `json:"AllReply"` | |
| TimeStamp string `json:"TimeStamp"` | |
| } | |
| // Value Set方法是flag.Value接口, 设置flag Value的方法. | |
| type Value interface { | |
| String() string | |
| Set(string) error | |
| } | |
| type arrayFlags []string | |
| func (i *arrayFlags) String() string { | |
| return fmt.Sprint(*i) | |
| } | |
| // 通过多个flag指定的值, 所以我们追加到最终的数组上. | |
| func (i *arrayFlags) Set(value string) error { | |
| *i = append(*i, value) | |
| return nil | |
| } | |
| func main() { | |
| keyfile := flag.String("keystore", "", "Keystore file") | |
| passwd := flag.String("passwd", "111111", "Password") | |
| url := flag.String("url", "http://47.56.150.104:8087", "Set node RPC URL") | |
| n := flag.Int("n", 1, "Test number") | |
| t := flag.Int("t", 1, "Duration") | |
| test := flag.String("test", "REQDCRMADDR", "REQDCRMADDR/LOCKOUT/EnodeSig/SetGroup/ACCEPTREQADDR/ACCEPTLOCKOUT") | |
| gid := flag.String("gid", "", "groupID") | |
| ts := flag.String("ts", "2/3", "Threshold") | |
| mode := flag.String("mode", "1", "Mode:private=1/managed=0") | |
| toAddr := flag.String("to", "0x0520e8e5E08169c4dbc1580Dc9bF56638532773A", "To address") | |
| value := flag.String("value", "10000000000000000", "lockout value") | |
| coin := flag.String("coin", "FSN", "Coin type") | |
| fromAddr := flag.String("from", "", "From address") | |
| memo := flag.String("memo", "smpcwallet.com", "Memo") | |
| accept := flag.String("accept", "AGREE", "AGREE/DISAGREE") | |
| key := flag.String("key", "", "Accept key") | |
| var enodesSig, nodes arrayFlags | |
| flag.Var(&enodesSig, "sig", "Enodes Sig list") | |
| flag.Var(&nodes, "node", "Node rpc url") | |
| flag.Parse() | |
| // To账户 | |
| toAccDef := accounts.Account{ | |
| Address: common.HexToAddress(DCRM_TO_ADDR), | |
| } | |
| fmt.Println("To address: = ", toAccDef.Address.String()) | |
| // 解析私钥文件 | |
| var keyjson []byte | |
| if *keyfile != "" { | |
| var err error | |
| keyjson, err = ioutil.ReadFile(*keyfile) | |
| if err != nil { | |
| fmt.Println("Read keystore fail", err) | |
| } | |
| } else { | |
| keyjson = []byte(KEYFILE) | |
| } | |
| keyWrapper, keyErr := keystore.DecryptKey(keyjson, *passwd) | |
| if keyErr != nil { | |
| fmt.Println("Key decrypt error:") | |
| panic(keyErr) | |
| } | |
| privateKey := hex.EncodeToString(keyWrapper.PrivateKey.D.Bytes()) | |
| fmt.Printf("PrivateKey = %s\n", privateKey) | |
| fmt.Printf("Recover from address = %s\n", keyWrapper.Address.String()) | |
| // 设置 signer and chain id | |
| chainID := big.NewInt(CHAIN_ID) | |
| signer := types.NewEIP155Signer(chainID) | |
| // 初始化RPC客户端 | |
| client := ethrpc.New(*url) | |
| fmt.Printf("HTTP-RPC client connected\n") | |
| enodeRep, err := client.Call("dcrm_getEnode") | |
| if err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("getEnode = %s\n\n", enodeRep) | |
| // 获取签名后的enode | |
| if *test == "EnodeSig" { | |
| var enodeJSON dataEnode | |
| enodeData, _ := getJSONData(enodeRep) | |
| if err := json.Unmarshal(enodeData, &enodeJSON); err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("enode = %s\n", enodeJSON.Enode) | |
| // 提取enode的pubkey | |
| s := strings.Split(enodeJSON.Enode, "@") | |
| enodePubkey := strings.Split(s[0], "//") | |
| fmt.Printf("enodePubkey = %s\n", enodePubkey[1]) | |
| sig, err := crypto.Sign(crypto.Keccak256([]byte(enodePubkey[1])), keyWrapper.PrivateKey) | |
| if err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("\nenodeSig self = \n%s\n\n", enodeJSON.Enode+common.ToHex(sig)) | |
| // 建组获取GID | |
| } else if *test == "SetGroup" { | |
| var enodeList []string | |
| // 通过-sig参数的enodesSig签名中获取enode列表建组 | |
| if len(enodesSig) > 0 { | |
| enodeList = make([]string, len(enodesSig)) | |
| for i := 0; i < len(enodesSig); i++ { | |
| s := strings.Split(enodesSig[i], "0x") | |
| enodeList[i] = s[0] | |
| fmt.Printf("enode[%d] = %s\n", i, enodeList[i]) | |
| } | |
| // 通过-node参数的节点rpc地址获取enode列表建组 | |
| } else if len(nodes) > 0 { | |
| enodeList = make([]string, len(nodes)) | |
| for i := 0; i < len(nodes); i++ { | |
| client := ethrpc.New(nodes[i]) | |
| enodeRep, err := client.Call("dcrm_getEnode") | |
| if err != nil { | |
| panic(err) | |
| } | |
| var enodeJSON dataEnode | |
| enodeData, _ := getJSONData(enodeRep) | |
| if err := json.Unmarshal(enodeData, &enodeJSON); err != nil { | |
| panic(err) | |
| } | |
| enodeList[i] = enodeJSON.Enode | |
| fmt.Printf("enode[%d] = %s\n", i, enodeList[i]) | |
| } | |
| } | |
| // 发送建组请求获取gid | |
| groupRep, err := client.Call("dcrm_createGroup", *ts, enodeList) | |
| if err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("dcrm_createGroup = %s\n", groupRep) | |
| var groupJSON groupInfo | |
| groupData, _ := getJSONData(groupRep) | |
| if err := json.Unmarshal(groupData, &groupJSON); err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("\nGid = %s\n\n", groupJSON.Gid) | |
| // 创建DCRM账户 | |
| } else if *test == "REQDCRMADDR" { | |
| // 获取 nonce | |
| reqAddrNonce, err := client.Call("dcrm_getReqAddrNonce", keyWrapper.Address.String()) | |
| if err != nil { | |
| panic(err) | |
| } | |
| nonceStr, _ := getJSONResult(reqAddrNonce) | |
| nonce, _ := strconv.ParseUint(nonceStr, 0, 64) | |
| fmt.Printf("dcrm_getReqAddrNonce = %s\nNonce = %d\n", reqAddrNonce, nonce) | |
| // 构建Sigs签名列表参数 | |
| sigs := "" | |
| if *mode == "0" { | |
| for i := 0; i < len(enodesSig)-1; i++ { | |
| sigs = sigs + enodesSig[i] + "|" | |
| } | |
| sigs = sigs + enodesSig[len(enodesSig)-1] | |
| } | |
| // 循环测试n次 | |
| keyIDList := make([]string, *n) | |
| for j := 0; j < *n; j++ { | |
| // 构建交易的data参数 | |
| timestamp := strconv.FormatInt((time.Now().UnixNano() / 1e6), 10) | |
| txdata := reqAddrData{ | |
| TxType: *test, | |
| GroupID: *gid, | |
| ThresHold: *ts, | |
| Mode: *mode, | |
| TimeStamp: timestamp, | |
| Sigs: sigs, | |
| } | |
| playload, _ := json.Marshal(txdata) | |
| // 签名交易 | |
| rawTX, err := signTX(signer, keyWrapper.PrivateKey, nonce, playload) | |
| if err != nil { | |
| panic(err) | |
| } | |
| nonce++ | |
| // 发送申请地址rawTx至节点rpc | |
| reqKeyID, err := client.Call("dcrm_reqDcrmAddr", rawTX) | |
| if err != nil { | |
| panic(err) | |
| } | |
| // 获取返回的keyID | |
| keyID, err := getJSONResult(reqKeyID) | |
| if err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("\ndcrm_reqDcrmAddr keyID = %s\n\n", keyID) | |
| keyIDList[j] = keyID | |
| time.Sleep(time.Duration(*t) * time.Second) | |
| } | |
| fmt.Printf("\nWaiting for stats result...\n") | |
| // 获取已生成所有账户列表 | |
| time.Sleep(time.Duration(20) * time.Second) | |
| accounts, err := client.Call("dcrm_getAccounts", keyWrapper.Address.String(), *mode) | |
| if err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("\naddress = %s\naccounts = %s\n\n", keyWrapper.Address.String(), accounts) | |
| // 根据keyID列表遍历查询申请地址失败的key | |
| time.Sleep(time.Duration(2) * time.Second) | |
| var statusJSON reqAddrStatus | |
| var i, j, k int | |
| for i, j, k = 0, 0, 0; j < *n; j++ { | |
| reqStatus, err := client.Call("dcrm_getReqAddrStatus", keyIDList[j]) | |
| if err != nil { | |
| fmt.Println("\ndcrm_getReqAddrStatus rpc error:", err) | |
| continue | |
| } | |
| statusJSONStr, err := getJSONResult(reqStatus) | |
| if err != nil { | |
| i++ | |
| fmt.Printf("\n%d\tdcrm_getReqAddrStatus=NotStart\tkeyID=%s ", i, keyIDList[j]) | |
| fmt.Println("\tRequest not complete:", err) | |
| continue | |
| } | |
| if err := json.Unmarshal([]byte(statusJSONStr), &statusJSON); err != nil { | |
| fmt.Println("\tUnmarshal statusJSONStr fail:", err) | |
| continue | |
| } | |
| if statusJSON.Status != "Success" { | |
| i++ | |
| fmt.Printf("\n%d\tdcrm_getReqAddrStatus=%s\tkeyID=%s ", i, statusJSON.Status, keyIDList[j]) | |
| } else { | |
| k++ | |
| fmt.Printf("Success=%d\tPubkey=%s\n", k, statusJSON.PubKey) | |
| } | |
| time.Sleep(time.Duration(100) * time.Millisecond) | |
| } | |
| // reqAddr统计结果 | |
| fmt.Printf("\nUser=%s request DCRM address Rate of Success %d / %d\n", keyWrapper.Address.String(), k, *n) | |
| // 审批创建共管账户 | |
| } else if *test == "ACCEPTREQADDR" { | |
| // 获取创建共管账户审批列表 | |
| reqListRep, err := client.Call("dcrm_getCurNodeReqAddrInfo", keyWrapper.Address.String()) | |
| if err != nil { | |
| panic(err) | |
| } | |
| reqListJSON, _ := getJSONData(reqListRep) | |
| fmt.Printf("dcrm_getCurNodeReqAddrInfo = %s\n", reqListJSON) | |
| // todo 生成未审批的key列表,自动审核通过发送同意审批交易。代替-key参数手动传入 | |
| for i := 0; i < 1; i++ { | |
| // 构建交易的data参数 | |
| timestamp := strconv.FormatInt((time.Now().UnixNano() / 1e6), 10) | |
| data := acceptData{ | |
| TxType: *test, | |
| Key: *key, | |
| Accept: *accept, | |
| TimeStamp: timestamp, | |
| } | |
| playload, err := json.Marshal(data) | |
| if err != nil { | |
| fmt.Println("error:", err) | |
| } | |
| // 签名交易 | |
| rawTX, err := signTX(signer, keyWrapper.PrivateKey, 0, playload) | |
| if err != nil { | |
| panic(err) | |
| } | |
| // 发送申请地址rawTx至节点rpc | |
| acceptReqAddrRep, err := client.Call("dcrm_acceptReqAddr", rawTX) | |
| if err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("\ndcrm_acceptReqAddr = %s\n\n", acceptReqAddrRep) | |
| // 获取返回的结果 | |
| reqRet, err := getJSONResult(acceptReqAddrRep) | |
| if err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("\ndcrm_acceptReq result = %s\n\n", reqRet) | |
| } | |
| // 测试发起交易 | |
| } else if *test == "LOCKOUT" { | |
| // 获取 lockout nonce | |
| lockoutNonce, err := client.Call("dcrm_getLockOutNonce", keyWrapper.Address.String()) | |
| if err != nil { | |
| panic(err) | |
| } | |
| nonceStr, err := getJSONResult(lockoutNonce) | |
| if err != nil { | |
| panic(err) | |
| } | |
| nonce, _ := strconv.ParseUint(nonceStr, 0, 64) | |
| fmt.Printf("dcrm_getLockOutNonce = %s\nNonce = %d\n", lockoutNonce, nonce) | |
| // 循环测试n次 | |
| keyIDList := make([]string, *n) | |
| for j := 0; j < *n; j++ { | |
| // 构建交易的data参数 | |
| timestamp := strconv.FormatInt((time.Now().UnixNano() / 1e6), 10) | |
| txdata := lockoutData{ | |
| TxType: *test, | |
| DcrmAddr: *fromAddr, | |
| DcrmTo: *toAddr, | |
| Value: *value, | |
| Cointype: *coin, | |
| GroupID: *gid, | |
| ThresHold: *ts, | |
| Mode: *mode, | |
| TimeStamp: timestamp, | |
| Memo: *memo, | |
| } | |
| playload, _ := json.Marshal(txdata) | |
| // 签名交易 | |
| rawTX, err := signTX(signer, keyWrapper.PrivateKey, nonce, playload) | |
| if err != nil { | |
| panic(err) | |
| } | |
| nonce++ | |
| // 发送申请地址rawTx至节点rpc | |
| reqKeyID, err := client.Call("dcrm_lockOut", rawTX) | |
| if err != nil { | |
| panic(err) | |
| } | |
| // 获取返回的keyID | |
| keyID, err := getJSONResult(reqKeyID) | |
| if err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("\ndcrm_lockOut keyID = %s\n\n", keyID) | |
| keyIDList[j] = keyID | |
| time.Sleep(time.Duration(*t) * time.Second) | |
| } | |
| fmt.Printf("\nWaiting for stats result...\n") | |
| // lockout根据keyID列表遍历查询申请地址失败的key | |
| time.Sleep(time.Duration(30) * time.Second) | |
| var statusJSON lockoutStatus | |
| var i, j, k int | |
| for i, j, k = 0, 0, 0; j < *n; j++ { | |
| reqStatus, err := client.Call("dcrm_getLockOutStatus", keyIDList[j]) | |
| if err != nil { | |
| fmt.Println("\ndcrm_getLockOutStatus rpc error:", err) | |
| continue | |
| } | |
| statusJSONStr, err := getJSONResult(reqStatus) | |
| if err != nil { | |
| i++ | |
| fmt.Printf("\n%d\tdcrm_getLockOutStatus=NotStart\tkeyID=%s ", i, keyIDList[j]) | |
| fmt.Println("\tRequest not complete:", err) | |
| continue | |
| } | |
| if err := json.Unmarshal([]byte(statusJSONStr), &statusJSON); err != nil { | |
| fmt.Println("\tUnmarshal statusJSONStr fail:", err) | |
| continue | |
| } | |
| if statusJSON.Status != "Success" { | |
| i++ | |
| fmt.Printf("\n%d\tdcrm_getLockOutStatus=%s\tkeyID=%s ", i, statusJSON.Status, keyIDList[j]) | |
| } else { | |
| k++ | |
| fmt.Printf("\nSuccess=%d\tOutTXhash=%s", k, statusJSON.OutTxHash) | |
| } | |
| time.Sleep(time.Duration(100) * time.Millisecond) | |
| } | |
| // lockout统计结果 | |
| fmt.Printf("\n\nUser=%s dcrm_LockOut Rate of Success %d / %d\n", keyWrapper.Address.String(), k, *n) | |
| // 审批共管账户发起交易 | |
| } else if *test == "ACCEPTLOCKOUT" { | |
| // 获取共管账户lockout审批列表 | |
| reqListRep, err := client.Call("dcrm_getCurNodeLockOutInfo", keyWrapper.Address.String()) | |
| if err != nil { | |
| panic(err) | |
| } | |
| reqListJSON, _ := getJSONData(reqListRep) | |
| fmt.Printf("dcrm_getCurNodeLockOutInfo = %s\n", reqListJSON) | |
| // todo 生成未审批的key列表,自动审核通过发送同意审批交易。代替-key参数手动传入 | |
| for i := 0; i < 1; i++ { | |
| // 构建交易的data参数 | |
| timestamp := strconv.FormatInt((time.Now().UnixNano() / 1e6), 10) | |
| data := acceptData{ | |
| TxType: *test, | |
| Key: *key, | |
| Accept: *accept, | |
| TimeStamp: timestamp, | |
| } | |
| playload, err := json.Marshal(data) | |
| if err != nil { | |
| fmt.Println("error:", err) | |
| } | |
| // 签名交易 | |
| rawTX, err := signTX(signer, keyWrapper.PrivateKey, 0, playload) | |
| if err != nil { | |
| panic(err) | |
| } | |
| // 发送rawTx至节点rpc | |
| acceptLockOutRep, err := client.Call("dcrm_acceptLockOut", rawTX) | |
| if err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("\ndcrm_acceptLockOut = %s\n\n", acceptLockOutRep) | |
| // 获取返回的结果 | |
| acceptRet, err := getJSONResult(acceptLockOutRep) | |
| if err != nil { | |
| panic(err) | |
| } | |
| fmt.Printf("\ndcrm_acceptLockOut result = %s\n\n", acceptRet) | |
| } | |
| } | |
| } | |
| // 解析rpc返回的data中result数据 | |
| func getJSONResult(successResponse json.RawMessage) (string, error) { | |
| var data dataResult | |
| repData, err := getJSONData(successResponse) | |
| if err != nil { | |
| return "", err | |
| } | |
| if err := json.Unmarshal(repData, &data); err != nil { | |
| fmt.Println("getJSONResult Unmarshal json fail:", err) | |
| return "", err | |
| } | |
| return data.Result, nil | |
| } | |
| func getJSONData(successResponse json.RawMessage) ([]byte, error) { | |
| var rep response | |
| if err := json.Unmarshal(successResponse, &rep); err != nil { | |
| fmt.Println("getJSONData Unmarshal json fail:", err) | |
| return nil, err | |
| } | |
| if rep.Status != "Success" { | |
| return nil, errors.New(rep.Error) | |
| } | |
| repData, err := json.Marshal(rep.Data) | |
| if err != nil { | |
| fmt.Println("getJSONData Marshal json fail:", err) | |
| return nil, err | |
| } | |
| return repData, nil | |
| } | |
| // 签名交易返回raw的十六进制字符串 | |
| func signTX(signer types.EIP155Signer, privatekey *ecdsa.PrivateKey, nonce uint64, playload []byte) (string, error) { | |
| toAccDef := accounts.Account{ | |
| Address: common.HexToAddress(DCRM_TO_ADDR), | |
| } | |
| // 建立交易 | |
| tx := types.NewTransaction( | |
| uint64(nonce), // nonce | |
| toAccDef.Address, // to address | |
| big.NewInt(0), // value | |
| 100000, // gasLimit | |
| big.NewInt(80000), // gasPrice | |
| playload) // data | |
| // 用私钥签署交易签名 | |
| signature, signatureErr := crypto.Sign(signer.Hash(tx).Bytes(), privatekey) | |
| if signatureErr != nil { | |
| fmt.Println("signature create error:") | |
| panic(signatureErr) | |
| } | |
| // 签名后构建完整交易 | |
| sigTx, signErr := tx.WithSignature(signer, signature) | |
| if signErr != nil { | |
| fmt.Println("signer with signature error:") | |
| panic(signErr) | |
| } | |
| // 获取raw TX | |
| txdata, txerr := rlp.EncodeToBytes(sigTx) | |
| if txerr != nil { | |
| panic(txerr) | |
| } | |
| rawTX := common.ToHex(txdata) | |
| fmt.Printf("\nSignTx:\nChainId\t\t=%s\nGas\t\t=%d\nGasPrice\t=%s\nNonce\t\t=%d\nToAddr\t\t=%s\nHash\t\t=%s\nData\t\t=%s\n", | |
| sigTx.ChainId(), sigTx.Gas(), sigTx.GasPrice(), sigTx.Nonce(), sigTx.To().String(), sigTx.Hash().Hex(), sigTx.Data()) | |
| fmt.Printf("RawTransaction = %+v\n", rawTX) | |
| return rawTX, nil | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment