|
1 | | -// (c) 2019-2020, Ava Labs, Inc. |
2 | | -// |
3 | | -// This file is a derived work, based on the go-ethereum library whose original |
4 | | -// notices appear below. |
5 | | -// |
6 | | -// It is distributed under a license compatible with the licensing terms of the |
7 | | -// original code from which it is derived. |
8 | | -// |
9 | | -// Much love to the original authors for their work. |
10 | | -// ********** |
11 | | -// Copyright 2014 The go-ethereum Authors |
12 | | -// This file is part of the go-ethereum library. |
13 | | -// |
14 | | -// The go-ethereum library is free software: you can redistribute it and/or modify |
15 | | -// it under the terms of the GNU Lesser General Public License as published by |
16 | | -// the Free Software Foundation, either version 3 of the License, or |
17 | | -// (at your option) any later version. |
18 | | -// |
19 | | -// The go-ethereum library is distributed in the hope that it will be useful, |
20 | | -// but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | | -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | | -// GNU Lesser General Public License for more details. |
23 | | -// |
24 | | -// You should have received a copy of the GNU Lesser General Public License |
25 | | -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. |
26 | | - |
27 | | -// Package types contains data types related to Ethereum consensus. |
28 | 1 | package types |
29 | | - |
30 | | -import ( |
31 | | - "encoding/binary" |
32 | | - "io" |
33 | | - "math/big" |
34 | | - "sync/atomic" |
35 | | - |
36 | | - "github.com/ava-labs/libevm/common" |
37 | | - "github.com/ava-labs/libevm/rlp" |
38 | | -) |
39 | | - |
40 | | -// Block represents an Ethereum block. |
41 | | -// |
42 | | -// Note the Block type tries to be 'immutable', and contains certain caches that rely |
43 | | -// on that. The rules around block immutability are as follows: |
44 | | -// |
45 | | -// - We copy all data when the block is constructed. This makes references held inside |
46 | | -// the block independent of whatever value was passed in. |
47 | | -// |
48 | | -// - We copy all header data on access. This is because any change to the header would mess |
49 | | -// up the cached hash and size values in the block. Calling code is expected to take |
50 | | -// advantage of this to avoid over-allocating! |
51 | | -// |
52 | | -// - When new body data is attached to the block, a shallow copy of the block is returned. |
53 | | -// This ensures block modifications are race-free. |
54 | | -// |
55 | | -// - We do not copy body data on access because it does not affect the caches, and also |
56 | | -// because it would be too expensive. |
57 | | -type Block struct { |
58 | | - header *Header |
59 | | - uncles []*Header |
60 | | - transactions Transactions |
61 | | - |
62 | | - // Coreth specific data structures to support atomic transactions |
63 | | - version uint32 |
64 | | - extdata *[]byte |
65 | | - |
66 | | - // caches |
67 | | - hash atomic.Value |
68 | | - size atomic.Value |
69 | | -} |
70 | | - |
71 | | -// "external" block encoding. used for eth protocol, etc. |
72 | | -type extblock struct { |
73 | | - Header *Header |
74 | | - Txs []*Transaction |
75 | | - Uncles []*Header |
76 | | - Version uint32 |
77 | | - ExtData *[]byte `rlp:"nil"` |
78 | | -} |
79 | | - |
80 | | -// NewBlock creates a new block. The input data is copied, changes to header and to the |
81 | | -// field values will not affect the block. |
82 | | -// |
83 | | -// The values of TxHash, UncleHash, ReceiptHash and Bloom in header |
84 | | -// are ignored and set to values derived from the given txs, uncles |
85 | | -// and receipts. |
86 | | -func NewBlock( |
87 | | - header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, hasher TrieHasher, |
88 | | -) *Block { |
89 | | - b := &Block{header: CopyHeader(header)} |
90 | | - |
91 | | - // TODO: panic if len(txs) != len(receipts) |
92 | | - if len(txs) == 0 { |
93 | | - b.header.TxHash = EmptyTxsHash |
94 | | - } else { |
95 | | - b.header.TxHash = DeriveSha(Transactions(txs), hasher) |
96 | | - b.transactions = make(Transactions, len(txs)) |
97 | | - copy(b.transactions, txs) |
98 | | - } |
99 | | - |
100 | | - if len(receipts) == 0 { |
101 | | - b.header.ReceiptHash = EmptyReceiptsHash |
102 | | - } else { |
103 | | - b.header.ReceiptHash = DeriveSha(Receipts(receipts), hasher) |
104 | | - b.header.Bloom = CreateBloom(receipts) |
105 | | - } |
106 | | - |
107 | | - if len(uncles) == 0 { |
108 | | - b.header.UncleHash = EmptyUncleHash |
109 | | - } else { |
110 | | - b.header.UncleHash = CalcUncleHash(uncles) |
111 | | - b.uncles = make([]*Header, len(uncles)) |
112 | | - for i := range uncles { |
113 | | - b.uncles[i] = CopyHeader(uncles[i]) |
114 | | - } |
115 | | - } |
116 | | - |
117 | | - return b |
118 | | -} |
119 | | - |
120 | | -// DecodeRLP decodes a block from RLP. |
121 | | -func (b *Block) DecodeRLP(s *rlp.Stream) error { |
122 | | - var eb extblock |
123 | | - _, size, _ := s.Kind() |
124 | | - if err := s.Decode(&eb); err != nil { |
125 | | - return err |
126 | | - } |
127 | | - b.header, b.uncles, b.transactions, b.version, b.extdata = eb.Header, eb.Uncles, eb.Txs, eb.Version, eb.ExtData |
128 | | - b.size.Store(rlp.ListSize(size)) |
129 | | - return nil |
130 | | -} |
131 | | - |
132 | | -// EncodeRLP serializes a block as RLP. |
133 | | -func (b *Block) EncodeRLP(w io.Writer) error { |
134 | | - return rlp.Encode(w, &extblock{ |
135 | | - Header: b.header, |
136 | | - Txs: b.transactions, |
137 | | - Uncles: b.uncles, |
138 | | - Version: b.version, |
139 | | - ExtData: b.extdata, |
140 | | - }) |
141 | | -} |
142 | | - |
143 | | -// Body returns the non-header content of the block. |
144 | | -// Note the returned data is not an independent copy. |
145 | | -func (b *Block) Body() *Body { |
146 | | - body := &Body{ |
147 | | - Transactions: b.transactions, |
148 | | - Uncles: b.uncles, |
149 | | - } |
150 | | - extra := &BodyExtra{ |
151 | | - Version: b.version, |
152 | | - ExtData: b.extdata, |
153 | | - } |
154 | | - return WithBodyExtra(body, extra) |
155 | | -} |
156 | | - |
157 | | -// Accessors for body data. These do not return a copy because the content |
158 | | -// of the body slices does not affect the cached hash/size in block. |
159 | | - |
160 | | -func (b *Block) Uncles() []*Header { return b.uncles } |
161 | | -func (b *Block) Transactions() Transactions { return b.transactions } |
162 | | - |
163 | | -func (b *Block) Transaction(hash common.Hash) *Transaction { |
164 | | - for _, transaction := range b.transactions { |
165 | | - if transaction.Hash() == hash { |
166 | | - return transaction |
167 | | - } |
168 | | - } |
169 | | - return nil |
170 | | -} |
171 | | - |
172 | | -// Header returns the block header (as a copy). |
173 | | -func (b *Block) Header() *Header { |
174 | | - return CopyHeader(b.header) |
175 | | -} |
176 | | - |
177 | | -// Header value accessors. These do copy! |
178 | | - |
179 | | -func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) } |
180 | | -func (b *Block) GasLimit() uint64 { return b.header.GasLimit } |
181 | | -func (b *Block) GasUsed() uint64 { return b.header.GasUsed } |
182 | | -func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) } |
183 | | -func (b *Block) Time() uint64 { return b.header.Time } |
184 | | -func (b *Block) Timestamp() uint64 { return b.header.Time } |
185 | | - |
186 | | -func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() } |
187 | | -func (b *Block) MixDigest() common.Hash { return b.header.MixDigest } |
188 | | -func (b *Block) Nonce() uint64 { return binary.BigEndian.Uint64(b.header.Nonce[:]) } |
189 | | -func (b *Block) Bloom() Bloom { return b.header.Bloom } |
190 | | -func (b *Block) Coinbase() common.Address { return b.header.Coinbase } |
191 | | -func (b *Block) Root() common.Hash { return b.header.Root } |
192 | | -func (b *Block) ParentHash() common.Hash { return b.header.ParentHash } |
193 | | -func (b *Block) TxHash() common.Hash { return b.header.TxHash } |
194 | | -func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash } |
195 | | -func (b *Block) UncleHash() common.Hash { return b.header.UncleHash } |
196 | | -func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) } |
197 | | - |
198 | | -func (b *Block) BaseFee() *big.Int { |
199 | | - if b.header.BaseFee == nil { |
200 | | - return nil |
201 | | - } |
202 | | - return new(big.Int).Set(b.header.BaseFee) |
203 | | -} |
204 | | - |
205 | | -func (b *Block) BeaconRoot() *common.Hash { return b.header.ParentBeaconRoot } |
206 | | - |
207 | | -func (b *Block) ExcessBlobGas() *uint64 { |
208 | | - var excessBlobGas *uint64 |
209 | | - if b.header.ExcessBlobGas != nil { |
210 | | - excessBlobGas = new(uint64) |
211 | | - *excessBlobGas = *b.header.ExcessBlobGas |
212 | | - } |
213 | | - return excessBlobGas |
214 | | -} |
215 | | - |
216 | | -func (b *Block) BlobGasUsed() *uint64 { |
217 | | - var blobGasUsed *uint64 |
218 | | - if b.header.BlobGasUsed != nil { |
219 | | - blobGasUsed = new(uint64) |
220 | | - *blobGasUsed = *b.header.BlobGasUsed |
221 | | - } |
222 | | - return blobGasUsed |
223 | | -} |
224 | | - |
225 | | -func (b *Block) BlockGasCost() *big.Int { |
226 | | - if HeaderExtras(b.header).BlockGasCost == nil { |
227 | | - return nil |
228 | | - } |
229 | | - return new(big.Int).Set(HeaderExtras(b.header).BlockGasCost) |
230 | | -} |
231 | | - |
232 | | -// Size returns the true RLP encoded storage size of the block, either by encoding |
233 | | -// and returning it, or returning a previously cached value. |
234 | | -func (b *Block) Size() uint64 { |
235 | | - if size := b.size.Load(); size != nil { |
236 | | - return size.(uint64) |
237 | | - } |
238 | | - c := writeCounter(0) |
239 | | - rlp.Encode(&c, b) |
240 | | - b.size.Store(uint64(c)) |
241 | | - return uint64(c) |
242 | | -} |
243 | | - |
244 | | -type writeCounter uint64 |
245 | | - |
246 | | -func (c *writeCounter) Write(b []byte) (int, error) { |
247 | | - *c += writeCounter(len(b)) |
248 | | - return len(b), nil |
249 | | -} |
250 | | - |
251 | | -func CalcUncleHash(uncles []*Header) common.Hash { |
252 | | - if len(uncles) == 0 { |
253 | | - return EmptyUncleHash |
254 | | - } |
255 | | - return rlpHash(uncles) |
256 | | -} |
257 | | - |
258 | | -// NewBlockWithHeader creates a block with the given header data. The |
259 | | -// header data is copied, changes to header and to the field values |
260 | | -// will not affect the block. |
261 | | -func NewBlockWithHeader(header *Header) *Block { |
262 | | - return &Block{header: CopyHeader(header)} |
263 | | -} |
264 | | - |
265 | | -// WithSeal returns a new block with the data from b but the header replaced with |
266 | | -// the sealed one. |
267 | | -func (b *Block) WithSeal(header *Header) *Block { |
268 | | - return &Block{ |
269 | | - header: CopyHeader(header), |
270 | | - transactions: b.transactions, |
271 | | - uncles: b.uncles, |
272 | | - } |
273 | | -} |
274 | | - |
275 | | -// WithBody returns a copy of the block with the given transaction and uncle contents. |
276 | | -func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block { |
277 | | - block := &Block{ |
278 | | - header: b.header, |
279 | | - transactions: make([]*Transaction, len(transactions)), |
280 | | - uncles: make([]*Header, len(uncles)), |
281 | | - } |
282 | | - copy(block.transactions, transactions) |
283 | | - for i := range uncles { |
284 | | - block.uncles[i] = CopyHeader(uncles[i]) |
285 | | - } |
286 | | - return block |
287 | | -} |
288 | | - |
289 | | -// Hash returns the keccak256 hash of b's header. |
290 | | -// The hash is computed on the first call and cached thereafter. |
291 | | -func (b *Block) Hash() common.Hash { |
292 | | - if hash := b.hash.Load(); hash != nil { |
293 | | - return hash.(common.Hash) |
294 | | - } |
295 | | - v := b.header.Hash() |
296 | | - b.hash.Store(v) |
297 | | - return v |
298 | | -} |
299 | | - |
300 | | -type Blocks []*Block |
0 commit comments