forked from newalchemylimited/seth
/
transaction.go
171 lines (141 loc) · 4.06 KB
/
transaction.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package seth
import (
"bytes"
)
// Transaction represents an ethereum transaction.
type Transaction struct {
Hash Hash `json:"hash"` // tx hash
Nonce Uint64 `json:"nonce"` // sender nonce
Block Hash `json:"blockHash"` // hash of parent block
BlockNumber Uint64 `json:"blockNumber"` //
To *Address `json:"to"` // receiver, or nil for contract creation
TxIndex *Uint64 `json:"transactionIndex"` // transaction index, or nil if pending
From *Address `json:"from"` // from
Value Int `json:"value"` // value in wei
GasPrice Int `json:"gasPrice"` // gas price
Gas Uint64 `json:"gas"` // gas spent on transaction
Input Data `json:"input"` // input data
}
// Encode returns an RLP encoded representation of the transaction. If a
// signature is provided, this will return an encoded representation containing
// the signature.
func (t *Transaction) Encode(sig *Signature) []byte {
var e rlpEncoder
if sig == nil {
e.EncodeTransaction(t)
} else {
e.EncodeSignedTx(t, sig)
}
return e.Bytes()
}
// HashToSign returns a hash which can be used to sign the transaction.
func (t *Transaction) HashToSign() *Hash {
var data, res rlpEncoder
data.EncodeTransaction(t)
data.EncodeInt(1)
data.EncodeInt(0)
data.EncodeInt(0)
res.EncodeList(data.Bytes())
hash := HashBytes(res.Bytes())
return &hash
}
// An rlpEncoder is a byte buffer that can RLP encode values.
type rlpEncoder bytes.Buffer
// Write proxies to bytes.Buffer.Write.
func (e *rlpEncoder) Write(b []byte) (n int, err error) {
return (*bytes.Buffer)(e).Write(b)
}
// Bytes proxies to bytes.Buffer.Bytes.
func (e *rlpEncoder) Bytes() []byte {
return (*bytes.Buffer)(e).Bytes()
}
func intBytes(n uint64) []byte {
var buf bytes.Buffer
shift := uint64(0)
for (n >> shift) > 0xFF {
shift += 8
}
for shift > 0 {
buf.Write([]byte{byte(n >> shift)})
shift -= 8
}
buf.Write([]byte{byte(n)})
return buf.Bytes()
}
// EncodeInt encodes an int.
func (e *rlpEncoder) EncodeInt(n uint64) {
if n == 0 {
e.Write([]byte{0x80})
} else {
e.EncodeBytes(intBytes(n), 0x80, 0xB7)
}
}
// EncodeString encodes a string.
func (e *rlpEncoder) EncodeString(b []byte) {
if len(b) == 0 {
e.Write([]byte{0x80})
} else if bytes.Equal(b, []byte{0x00}) {
e.Write([]byte{0x00})
} else {
e.EncodeBytes(b, 0x80, 0xB7)
}
}
// EncodeList encodes a list of bytes.
func (e *rlpEncoder) EncodeList(b []byte) {
if len(b) == 1 && b[0] == 0x00 {
e.Write([]byte{0x80})
} else {
e.EncodeBytes(b, 0xC0, 0xF7)
}
}
// EncodeBytes encodes bytes using sh or lh as headers depending on len(b).
func (e *rlpEncoder) EncodeBytes(b []byte, sh byte, lh byte) {
if len(b) == 1 && b[0] < 0x80 {
e.Write(b)
return
}
if len(b) < 56 {
e.Write([]byte{byte(int(sh) + len(b))})
} else {
blen := intBytes(uint64(len(b)))
e.Write([]byte{byte(int(lh) + len(blen))})
e.Write(blen)
}
e.Write(b)
}
// EncodeTransaction encodes the given transaction.
func (e *rlpEncoder) EncodeTransaction(t *Transaction) {
e.EncodeInt(uint64(t.Nonce))
e.EncodeString(t.GasPrice.Big().Bytes())
e.EncodeInt(uint64(t.Gas))
if t.To == nil {
e.EncodeString(nil)
} else {
e.EncodeString(t.To[:])
}
e.EncodeString(t.Value.Big().Bytes())
e.EncodeString(t.Input)
return
}
// EncodeSignedTx encodes a transaction with the given signature.
func (e *rlpEncoder) EncodeSignedTx(t *Transaction, sig *Signature) {
var buf rlpEncoder
buf.EncodeTransaction(t)
r, s, v := sig.Parts()
buf.EncodeInt(uint64(v) + 37)
buf.EncodeString(r.Bytes())
buf.EncodeString(s.Bytes())
e.EncodeList(buf.Bytes())
}
// A Signer is a function capable of signing a hash.
type Signer func(*Hash) (*Signature, error)
// SignTransaction produces a signed, serialized 'raw' transaction
// from the given transaction and signer.
func SignTransaction(t *Transaction, sign Signer) ([]byte, error) {
hash := t.HashToSign()
sig, err := sign(hash)
if err != nil {
return nil, err
}
return t.Encode(sig), nil
}