http://www.7klian.com

以太坊生意业务签名进程源码理会

    methodId := crypto.Keccak256([]byte(“setA(uint256)”))[:4]
    Price        *big.Int        `json:”gasPrice” gencodec:”required”`
func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
    return cpy, nil
    // 三、生意业务签名
    if len(hash) != 32 {
    jsonSigTx, _ := sigTransaction.MarshalJSON()
        return
}
    Recipient    *common.Address `json:”to”       rlp:”nil”` // nil means contract creation
        a = _a;
至此,生意业务的签名已完成,获得了签名数据。从原始数据到签名数据,焦点的技能点包罗:
    fmt.Println(“sigTransaction: “, string(jsonSigTx))
    if err != nil {
    V *big.Int `json:”v” gencodec:”required”`
        tx.data.Recipient,
        return a;
    }
假如是陈设合约时,address为空。假如是以太币转账生意业务, input为空,address为吸收者地点。
    “github.com/ethereum/go-ethereum/common”
六、总结
    seckey := math.PaddedBigBytes(prv.D, prv.Params().BitSize/8)
•methodId,,函数标识码(4个字节),对setA(uint256)求Keccak256,然后取前4位,值为:ee919d50。
func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
    }
crypto.Sign(h[:], prv)源代码如下所示。
结构生意业务工具需要的参数包罗:
    nonce := uint64(24)
    input := append(methodId, paramValue…)
    uint256 internal a;
    GasLimit     uint64          `json:”gas”      gencodec:”required”`
    }
    Payload      []byte          `json:”input”    gencodec:”required”`
•按照签名功效计较V,R,S
    }
    cpy := &Transaction{data: tx.data}
func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
    value := big.NewInt(0)
}
    }
        Recipient:    to,
}
    cpy.data.R, cpy.data.S, cpy.data.V = r, s, v
    size atomic.Value
    }
type Transaction struct {
}
•合约要领及参数举办ABI编码
    return r, s, v, nil
    if len(sig) != 65 {
import (
    }
    return tx.WithSignature(s, sig)
}
}
•对编码后生意业务数据利用私钥举办椭圆曲线签名获得签名串
    gasLimit := uint64(3000000)
•s Signer,signer签名方法,包罗EIP155Signer,HomesteadSigner和FrontierSigner,个中HomesteadSigner担任FrontierSigner。之所以需要该字段,是因为在EIP155中修复了简朴反复进攻裂痕后,需要保持旧的签名方法稳定,但又需要提供新版本的签名方法。因此按照区块高度建设差异的签名器。
    })
    from atomic.Value
        s.chainId, uint(0), uint(0),
    fmt.Println(“paramValue: “, common.Bytes2Hex(paramValue))
    }
    “fmt”
生意业务签名焦点挪用types.SignTx要领,源码如下所示。
rawTx:  {“nonce”:”0x18″,”gasPrice”:”0x4a817c800″,”gas”:”0x2dc6c0″,”to”:”0x05e56888360ae54acf2a389bab39bd41e3934d2b”,”value”:”0x0″,”input”:”0xee919d50000000000000000000000000000000000000000000000000000000000000007b”,”v”:”0x0″,”r”:”0x0″,”s”:”0x0″,”hash”:”0x629d42fd16be0b5dc22d53d63dcce8144d5fc843e056465bc2bea25f4ebe8249″}
在WithSignature要领中,焦点挪用了SignatureValues要领。 EIP155Signer的SignatureValues要领对比FrontierSigner的要领,区别是在计较V值上。
    // caches
func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
•对签名后的生意业务工具举办RLP编码获得签名后的生意业务数据
4.1 计较rlpHash
        tx.data.Price,
        Amount:       new(big.Int),
Hash计较代码如下所示。
        tx.data.Amount,
这个数据包括两部门:
4.3 填充生意业务工具中的V,R,S字段
    function getA() public view returns (uint256) {
}
我以一个简朴合约为例,挪用合约的setA要领,参数为123。合约代码如下。
}
    data txdata
    AccountNonce uint64          `json:”nonce”    gencodec:”required”`
    hash atomic.Value
        data = common.CopyBytes(data)
    data, err := rlp.EncodeToBytes(tx)
    “math/big”
4.2 私钥签名
    S *big.Int `json:”s” gencodec:”required”`
三、结构Transaction工具
•生意业务信息rpl编码
    // 二、结构生意业务工具
    “github.com/ethereum/go-ethereum/common/math”
Sign要领挪用secp256k1的椭圆曲线算法举办签名,签名后返回功效为: 41c4a2eb073e6df89c3f467b3516e9c313590d8d57f7c217fe7e72a7b4a6b8ed5f20a758396a5e681ce1ab4cec749f8560e28c9eb91072ec7a8acc002a11bb1d00
        AccountNonce: nonce,
    if err != nil {
}
    // 四、发送生意业务
    if s.chainId.Sign() != 0 {
// go-ethereum/core/types/transaction_signing.go
    R, S, V, err = HomesteadSigner{}.SignatureValues(tx, sig)
•gasPrice,gas 价值
    }
    }
}
        tx.data.GasLimit,
package main
•椭圆曲线secp256k1签名
        fmt.Println(“types.SignTx failed: “, err.Error())
签名后的生意业务工具功效为: {“nonce”:”0x18″,”gasPrice”:”0x4a817c800″,”gas”:”0x2dc6c0″,”to”:”0x05e56888360ae54acf2a389bab39bd41e3934d2b”,”value”:”0x0″,”input”:”0xee919d50000000000000000000000000000000000000000000000000000000000000007b”,”v”:”0x25″,”r”:”0x41c4a2eb073e6df89c3f467b3516e9c313590d8d57f7c217fe7e72a7b4a6b8ed”,”s”:”0x5f20a758396a5e681ce1ab4cec749f8560e28c9eb91072ec7a8acc002a11bb1d”,”hash”:”0xf8a3bf13828d50b107da40188c8e772b83a613f0044593a4e49438a214a79c83″}
一、筹备事情
四、生意业务签名
    }
EIP155Signer实现的hash算法对比FrontierSigner多了一个链ID和两个uint空值,这样的话,一笔已签名的生意业务只大概属于一条链。
    if tx.IsPrivate() {
func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
FrontierSigner的SignatureValues要领中,将签名功效41c4a2eb073e6df89c3f467b3516e9c313590d8d57f7c217fe7e72a7b4a6b8ed5f20a758396a5e681ce1ab4cec749f8560e28c9eb91072ec7a8acc002a11bb1d00分为三份,别离是:
•前32字节的R,41c4a2eb073e6df89c3f467b3516e9c313590d8d57f7c217fe7e72a7b4a6b8ed
    function setA(uint256 _a) public {
•按照签名串生成签名后生意业务工具
•paramValue,函数参数(32字节),对值为123的BigInt范例转byte,值为:,000000000000000000000000000000000000000000000000000000000000007b
        v = new(big.Int).SetBytes([]byte{sig[64] + 27})
•生意业务工具RLP编码
•gasLimit,最大耗损gas
    signer := types.NewEIP155Signer(big.NewInt(1))
    h := s.Hash(tx)
        tx.data.AccountNonce,
        Payload:      data,
    defer zeroBytes(seckey)
从请求代码中也可以看出,数据流转的
进程包罗:
    sig, err := crypto.Sign(h[:], prv)
        return nil, nil, nil, err
    // 一、ABI编码请求参数
        v = new(big.Int).SetBytes([]byte{sig[64] + 37})
    gasPrice := big.NewInt(20000000000)
    if len(data) > 0 {
    r = new(big.Int).SetBytes(sig[:32])
func main() {
}
// go-ethereum/core/types/transaction.go
    Hash *common.Hash `json:”hash” rlp:”-“`
// go-ethereum/core/types/transaction_signing.go
    rawTx := types.NewTransaction(nonce, common.HexToAddress(“0x05e56888360ae54acf2a389bab39bd41e3934d2b”), value, gasLimit, gasPrice, input)
        fmt.Println(“ethclient.Dial failed: “, err.Error())
        d.Price.Set(gasPrice)
    “github.com/ethereum/go-ethereum/core/types”
type txdata struct {
    return &Transaction{data: d}
    Amount       *big.Int        `json:”value”    gencodec:”required”`
    fmt.Println(“methodId: “, common.Bytes2Hex(methodId))
contract Test {
        return nil, err
二、ABI编码请求参数
    }
        panic(fmt.Sprintf(“wrong size for signature: got %d, want 65”, len(sig)))
    err = ethClient.SendTransaction(context.Background(), sigTransaction)
        emit SetA(msg.sender, _a);
生意业务的焦点数据布局是txdata。
        GasLimit:     gasLimit,
        V.Add(V, s.chainIdMul)
        V = big.NewInt(int64(sig[64] + 35))
0xf889188504a817c800832dc6c09405e56888360ae54acf2a389bab39bd41e3934d2b80a4ee919d50000000000000000000000000000000000000000000000000000000000000007b25a041c4a2eb073e6df89c3f467b3516e9c313590d8d57f7c217fe7e72a7b4a6b8eda05f20a758396a5e681ce1ab4cec749f8560e28c9eb91072ec7a8acc002a11bb1d
func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
    return secp256k1.Sign(hash, seckey)
        fmt.Println(“crypto.HexToECDSA failed: “, err.Error())
挪用代码如下所示。
    }
    fmt.Println(“rawTx: “, string(jsonRawTx))
    }
    jsonRawTx, _ := rawTx.MarshalJSON()
    if err != nil {
        fmt.Println(“ethClient.SendTransaction failed: “, err.Error())
    // Signature values
    “github.com/ethereum/go-ethereum/crypto”
    if amount != nil {

网络提倡一笔生意业务时,需要利用私钥对生意业务举办签名。那么从原始的请求数据到最终的签名后的数据,这中间的数据流转是奈何的,颠末尾什么进程,本日从go-ethereum源码入手,理会下数据的转换。
setA(123)颠末ABI编码后获得的数据是: 0xee919d50000000000000000000000000000000000000000000000000000000000000007b
•address,合约地点
3.填充生意业务工具中的V,R,S字段
    if err != nil {
        V:            new(big.Int),
        return nil, err
func (hs HomesteadSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
    “context”
    if err != nil {
    r, s, v, err := signer.SignatureValues(tx, sig)
发送生意业务SendTransaction要领首先会对具有签名信息的生意业务工具举办rlp编码,编码后挪用的jsonrpc的eth_sendRawTransaction要领发送生意业务。源代码如下所示:
        tx.data.Payload,
    if err != nil {
•tx *Transaction,结构Transaction工具
•最后一个字节00加上27,获得V,十进制为27
}
    if gasPrice != nil {
•ABI编码
    ethClient, err := ethclient.Dial(“http://127.0.0.1:7545”)
    event SetA(address indexed _from, uint256 _value);
在txdata中的V,R,S三个字段是与签名相关。结构后的生意业务工具输出功效为(此时v、r、s为默认空值):
// go-ethereum/core/types/transaction_signing.go
rlpHash的计较功效为: 0x9ef7f101dae55081553998d52d0ce57c4cf37271f800b70c0863c4a749977ef1
pragma solidity >=0.4.22 <0.6.0;
        Price:        new(big.Int),
        return
        d.Amount.Set(amount)
    return hs.FrontierSigner.SignatureValues(tx, sig)
// SignTx signs the transaction using the given signer and private key
        return
    “github.com/ethereum/go-ethereum/ethclient”
    }
    return rlpHash([]interface{}{
    sigTransaction, err := types.SignTx(rawTx, signer, key)
•结构Transaction生意业务工具
        R:            new(big.Int),
    fmt.Println(“send transaction success,tx: “, sigTransaction.Hash().Hex())
•nonce,请求账号nonce值
    s = new(big.Int).SetBytes(sig[32:64])
// go-ethereum/ethclient/ethclient.go
func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
        return nil, fmt.Errorf(“hash is required to be exactly 32 bytes (%d)”, len(hash))
}
        return
)
tx.WithSignature(s, sig)源代码如下所示。
    }
    return ec.c.CallContext(ctx, nil, “eth_sendRawTransaction”, common.ToHex(data))
    }
    R *big.Int `json:”r” gencodec:”required”`
    fmt.Println(“input: “, common.Bytes2Hex(input))
SignTx要领的签名进程分为三步:
    if err != nil {
    if err != nil {
在EIP155Signer的SignatureValues要领中,按照链ID从头计较V值,我这里的链ID是1,从头计较获得的V值十进制功效是37。
        S:            new(big.Int),
•input,请求的合约输入参数
    d := txdata{
五、发送生意业务
    // This is only used when marshaling to JSON.
    return R, S, V, nil
•value,转账的以太币个数,单元wei
    key, err := crypto.HexToECDSA(“e8e14120bb5c085622253540e886527d24746cd42d764a5974be47090d3cbc42”)
最终计较获得的签名后的生意业务数据为: 
•中间32字节的S,5f20a758396a5e681ce1ab4cec749f8560e28c9eb91072ec7a8acc002a11bb1d
    paramValue := math.U256Bytes(new(big.Int).Set(big.NewInt(123)))
    } else {
2.对rlpHash利用私钥举办签名
1.对生意业务信息计较rlpHash
func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error {
参考:https://learnblockchain.cn/books/geth/part3/sign-and-valid.html

// go-ethereum/crypto/signature_cgo.go
SignTx要领有三个参数:
•prv *ecdsa.PrivateKey,secp256k1尺度的私钥
    }
        return err

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

相关文章阅读