/
tx.go
139 lines (119 loc) · 3.14 KB
/
tx.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// 以太坊工具箱(零第三方库依赖) 版权 @2019 柴树杉。
package ethutil
import (
"bytes"
"math/big"
"golang.org/x/crypto/sha3"
"github.com/chai2010/ethutil/rlp"
)
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
// FORK_BLKNUM: 2,675,000
// CHAIN_ID: 1 (main net)
// EIP分叉时区块高度
// 之后交易的签名数据从6个变成9个
const EIP155_FORK_BLKNUM = 2675000
// 交易数据
type TxData struct {
Nonce uint64
GasPrice string
GasLimit string
To string // 0地址 表示合约
Value string
Data []byte
V *big.Int
R *big.Int
S *big.Int
}
// RLP编码签名过后的交易
func (p *TxData) EncodeRLP() []byte {
var buf bytes.Buffer
rlp.Encode(&buf, p)
return buf.Bytes()
}
// 生成最新规范的要签名编码数据
func (p *TxData) SigData() []byte {
// 输出EIP55之后的格式, 不包含 chainId
return p.sigData(0, EIP155_FORK_BLKNUM)
}
// 生成要签名编码数据(支持旧规范)
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
func (p *TxData) SigDataEx(chainId, blockNumber int64) []byte {
// 输出EIP55之后的格式, 包含 chainId
return p.sigData(chainId, blockNumber)
}
// 计算交易的哈希(可用于后续的签名)
func (p *TxData) Hash() []byte {
keccak256 := sha3.NewLegacyKeccak256()
keccak256.Write(p.SigData())
return keccak256.Sum(nil)
}
// 计算交易的哈希
func (p *TxData) HashEx(chainId, blockNumber int64) []byte {
keccak256 := sha3.NewLegacyKeccak256()
keccak256.Write(p.SigDataEx(chainId, blockNumber))
return keccak256.Sum(nil)
}
// 输出用于签名hash的RLP编码数据
func (p *TxData) sigData(chainId, blockNumber int64) []byte {
// 解码Hex格式地址
// 如果是零地址, 用 nil 表示
var p_To *[20]byte
if !Hex(p.To).IsZero() {
var address [20]byte
copy(address[:], Hex(p.To).MustBytes())
p_To = &address
}
// 初始规范只编码交易的6个信息
if blockNumber < EIP155_FORK_BLKNUM {
var txData = &struct {
Nonce uint64
GasPrice *big.Int
GasLimit uint64
To *[20]byte // nil 表示合约
Value *big.Int
Data []byte
}{
Nonce: p.Nonce,
GasPrice: MustBigint(p.GasPrice, 0),
GasLimit: MustUint64(p.GasLimit, 0),
To: p_To,
Value: MustBigint(p.Value, 0),
Data: p.Data,
}
var buf bytes.Buffer
rlp.Encode(&buf, txData)
return buf.Bytes()
}
// EIP155之后增加 V/R/S 三个元素
// V 可以包含 chainId, 但是依然兼容以前旧的风格
// 因为增加来内容, 导致旧版本的客户端不再兼容
var txData = &struct {
Nonce uint64
GasPrice *big.Int
GasLimit uint64
To *[20]byte // nil 表示合约
Value *big.Int
Data []byte
V *big.Int
R *big.Int
S *big.Int
}{
Nonce: p.Nonce,
GasPrice: MustBigint(p.GasPrice, 0),
GasLimit: MustUint64(p.GasLimit, 0),
To: p_To,
Value: MustBigint(p.Value, 0),
Data: p.Data,
}
// 包含 chainId 信息
if chainId > 0 {
// v = CHAIN_ID * 2 + 35 or v = CHAIN_ID * 2 + 36
txData.V = big.NewInt(chainId)
} else {
txData.V = big.NewInt(27)
}
// RLP编码
var buf bytes.Buffer
rlp.Encode(&buf, txData)
return buf.Bytes()
}