diff options
author | Felix Lange <fjl@twurst.com> | 2015-06-16 18:41:50 +0800 |
---|---|---|
committer | Jeffrey Wilcke <geffobscura@gmail.com> | 2015-06-30 00:51:47 +0800 |
commit | 1d42888d3047dabfb352c94a2051e7af14d2a509 (patch) | |
tree | 8ca68ca98bd697f26f2033a5480e78ccbf064162 /core/types | |
parent | 654564e164b3b6f7f4ba1e8bbd6fcd64776068fa (diff) | |
download | go-tangerine-1d42888d3047dabfb352c94a2051e7af14d2a509.tar go-tangerine-1d42888d3047dabfb352c94a2051e7af14d2a509.tar.gz go-tangerine-1d42888d3047dabfb352c94a2051e7af14d2a509.tar.bz2 go-tangerine-1d42888d3047dabfb352c94a2051e7af14d2a509.tar.lz go-tangerine-1d42888d3047dabfb352c94a2051e7af14d2a509.tar.xz go-tangerine-1d42888d3047dabfb352c94a2051e7af14d2a509.tar.zst go-tangerine-1d42888d3047dabfb352c94a2051e7af14d2a509.zip |
core/types: make blocks immutable
Diffstat (limited to 'core/types')
-rw-r--r-- | core/types/block.go | 421 |
1 files changed, 184 insertions, 237 deletions
diff --git a/core/types/block.go b/core/types/block.go index d7963981e..31ea478d4 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -15,71 +15,59 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) -type Header struct { - // Hash to the previous block - ParentHash common.Hash - // Uncles of this block - UncleHash common.Hash - // The coin base address - Coinbase common.Address - // Block Trie state - Root common.Hash - // Tx sha - TxHash common.Hash - // Receipt sha - ReceiptHash common.Hash - // Bloom - Bloom Bloom - // Difficulty for the current block - Difficulty *big.Int - // The block number - Number *big.Int - // Gas limit - GasLimit *big.Int - // Gas used - GasUsed *big.Int - // Creation time - Time uint64 - // Extra data - Extra []byte - // Mix digest for quick checking to prevent DOS - MixDigest common.Hash - // Nonce - Nonce [8]byte -} +// A BlockNonce is a 64-bit hash which proves (combined with the +// mix-hash) that a suffcient amount of computation has been carried +// out on a block. +type BlockNonce [8]byte -func (self *Header) Hash() common.Hash { - return rlpHash(self.rlpData(true)) +func EncodeNonce(i uint64) BlockNonce { + var n BlockNonce + binary.BigEndian.PutUint64(n[:], i) + return n } -func (self *Header) HashNoNonce() common.Hash { - return rlpHash(self.rlpData(false)) +func (n BlockNonce) Uint64() uint64 { + return binary.BigEndian.Uint64(n[:]) } -func (self *Header) rlpData(withNonce bool) []interface{} { - fields := []interface{}{ - self.ParentHash, - self.UncleHash, - self.Coinbase, - self.Root, - self.TxHash, - self.ReceiptHash, - self.Bloom, - self.Difficulty, - self.Number, - self.GasLimit, - self.GasUsed, - self.Time, - self.Extra, - } - if withNonce { - fields = append(fields, self.MixDigest, self.Nonce) - } - return fields -} - -func (self *Header) RlpData() interface{} { - return self.rlpData(true) +type Header struct { + ParentHash common.Hash // Hash to the previous block + UncleHash common.Hash // Uncles of this block + Coinbase common.Address // The coin base address + Root common.Hash // Block Trie state + TxHash common.Hash // Tx sha + ReceiptHash common.Hash // Receipt sha + Bloom Bloom // Bloom + Difficulty *big.Int // Difficulty for the current block + Number *big.Int // The block number + GasLimit *big.Int // Gas limit + GasUsed *big.Int // Gas used + Time uint64 // Creation time + Extra []byte // Extra data + MixDigest common.Hash // for quick difficulty verification + Nonce BlockNonce +} + +func (h *Header) Hash() common.Hash { + return rlpHash(h) +} + +func (h *Header) HashNoNonce() common.Hash { + return rlpHash([]interface{}{ + h.ParentHash, + h.UncleHash, + h.Coinbase, + h.Root, + h.TxHash, + h.ReceiptHash, + h.Bloom, + h.Difficulty, + h.Number, + h.GasLimit, + h.GasUsed, + h.Time, + h.Extra, + }) } func (h *Header) UnmarshalJSON(data []byte) error { @@ -112,20 +100,14 @@ func rlpHash(x interface{}) (h common.Hash) { } type Block struct { - // Preset Hash for mock (Tests) - HeaderHash common.Hash - ParentHeaderHash common.Hash - // ^^^^ ignore ^^^^ - header *Header uncles []*Header transactions Transactions - Td *big.Int - queued bool // flag for blockpool to skip TD check + receipts Receipts + Td *big.Int + queued bool // flag for blockpool to skip TD check ReceivedAt time.Time - - receipts Receipts } // StorageBlock defines the RLP encoding of a Block stored in the @@ -148,43 +130,90 @@ type storageblock struct { TD *big.Int } -func NewBlock(parentHash common.Hash, coinbase common.Address, root common.Hash, difficulty *big.Int, nonce uint64, extra []byte) *Block { - header := &Header{ - Root: root, - ParentHash: parentHash, - Coinbase: coinbase, - Difficulty: difficulty, - Time: uint64(time.Now().Unix()), - Extra: extra, - GasUsed: new(big.Int), - GasLimit: new(big.Int), - Number: new(big.Int), +var ( + emptyRootHash = DeriveSha(Transactions{}) + emptyUncleHash = CalcUncleHash(nil) +) + +// NewBlock creates a new block. The input data is copied, +// changes to header and to the field values will not affect the +// block. +// +// The values of TxHash, UncleHash, ReceiptHash and Bloom in header +// are ignored and set to values derived from the given txs, uncles +// and receipts. +func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt) *Block { + b := &Block{header: copyHeader(header), Td: new(big.Int)} + + // TODO: panic if len(txs) != len(receipts) + if len(txs) == 0 { + b.header.TxHash = emptyRootHash + } else { + b.header.TxHash = DeriveSha(Transactions(txs)) + b.transactions = make(Transactions, len(txs)) + copy(b.transactions, txs) } - header.SetNonce(nonce) - block := &Block{header: header} - block.Td = new(big.Int) - return block -} + if len(receipts) == 0 { + b.header.ReceiptHash = emptyRootHash + } else { + b.header.ReceiptHash = DeriveSha(Receipts(receipts)) + b.header.Bloom = CreateBloom(receipts) + b.receipts = make([]*Receipt, len(receipts)) + copy(b.receipts, receipts) + } -func (self *Header) SetNonce(nonce uint64) { - binary.BigEndian.PutUint64(self.Nonce[:], nonce) + if len(uncles) == 0 { + b.header.UncleHash = emptyUncleHash + } else { + b.header.UncleHash = CalcUncleHash(uncles) + b.uncles = make([]*Header, len(uncles)) + for i := range uncles { + b.uncles[i] = copyHeader(uncles[i]) + } + } + + return b } +// NewBlockWithHeader creates a block with the given header data. The +// header data is copied, changes to header and to the field values +// will not affect the block. func NewBlockWithHeader(header *Header) *Block { - return &Block{header: header} + return &Block{header: copyHeader(header)} +} + +func copyHeader(h *Header) *Header { + cpy := *h + if cpy.Difficulty = new(big.Int); h.Difficulty != nil { + cpy.Difficulty.Set(h.Difficulty) + } + if cpy.Number = new(big.Int); h.Number != nil { + cpy.Number.Set(h.Number) + } + if cpy.GasLimit = new(big.Int); h.GasLimit != nil { + cpy.GasLimit.Set(h.GasLimit) + } + if cpy.GasUsed = new(big.Int); h.GasUsed != nil { + cpy.GasUsed.Set(h.GasUsed) + } + if len(h.Extra) > 0 { + cpy.Extra = make([]byte, len(h.Extra)) + copy(cpy.Extra, h.Extra) + } + return &cpy } -func (self *Block) ValidateFields() error { - if self.header == nil { +func (b *Block) ValidateFields() error { + if b.header == nil { return fmt.Errorf("header is nil") } - for i, transaction := range self.transactions { + for i, transaction := range b.transactions { if transaction == nil { return fmt.Errorf("transaction %d is nil", i) } } - for i, uncle := range self.uncles { + for i, uncle := range b.uncles { if uncle == nil { return fmt.Errorf("uncle %d is nil", i) } @@ -192,64 +221,48 @@ func (self *Block) ValidateFields() error { return nil } -func (self *Block) DecodeRLP(s *rlp.Stream) error { +func (b *Block) DecodeRLP(s *rlp.Stream) error { var eb extblock if err := s.Decode(&eb); err != nil { return err } - self.header, self.uncles, self.transactions = eb.Header, eb.Uncles, eb.Txs + b.header, b.uncles, b.transactions = eb.Header, eb.Uncles, eb.Txs return nil } -func (self Block) EncodeRLP(w io.Writer) error { +func (b Block) EncodeRLP(w io.Writer) error { return rlp.Encode(w, extblock{ - Header: self.header, - Txs: self.transactions, - Uncles: self.uncles, + Header: b.header, + Txs: b.transactions, + Uncles: b.uncles, }) } -func (self *StorageBlock) DecodeRLP(s *rlp.Stream) error { +func (b *StorageBlock) DecodeRLP(s *rlp.Stream) error { var sb storageblock if err := s.Decode(&sb); err != nil { return err } - self.header, self.uncles, self.transactions, self.Td = sb.Header, sb.Uncles, sb.Txs, sb.TD + b.header, b.uncles, b.transactions, b.Td = sb.Header, sb.Uncles, sb.Txs, sb.TD return nil } -func (self StorageBlock) EncodeRLP(w io.Writer) error { +func (b StorageBlock) EncodeRLP(w io.Writer) error { return rlp.Encode(w, storageblock{ - Header: self.header, - Txs: self.transactions, - Uncles: self.uncles, - TD: self.Td, + Header: b.header, + Txs: b.transactions, + Uncles: b.uncles, + TD: b.Td, }) } -func (self *Block) Header() *Header { - return self.header -} - -func (self *Block) Uncles() []*Header { - return self.uncles -} - -func (self *Block) CalculateUnclesHash() common.Hash { - return rlpHash(self.uncles) -} +// TODO: copies +func (b *Block) Uncles() []*Header { return b.uncles } +func (b *Block) Transactions() Transactions { return b.transactions } +func (b *Block) Receipts() Receipts { return b.receipts } -func (self *Block) SetUncles(uncleHeaders []*Header) { - self.uncles = uncleHeaders - self.header.UncleHash = rlpHash(uncleHeaders) -} - -func (self *Block) Transactions() Transactions { - return self.transactions -} - -func (self *Block) Transaction(hash common.Hash) *Transaction { - for _, transaction := range self.transactions { +func (b *Block) Transaction(hash common.Hash) *Transaction { + for _, transaction := range b.transactions { if transaction.Hash() == hash { return transaction } @@ -257,74 +270,33 @@ func (self *Block) Transaction(hash common.Hash) *Transaction { return nil } -func (self *Block) SetTransactions(transactions Transactions) { - self.transactions = transactions - self.header.TxHash = DeriveSha(transactions) -} -func (self *Block) AddTransaction(transaction *Transaction) { - self.transactions = append(self.transactions, transaction) - self.SetTransactions(self.transactions) -} - -func (self *Block) Receipts() Receipts { - return self.receipts -} - -func (self *Block) SetReceipts(receipts Receipts) { - self.receipts = receipts - self.header.ReceiptHash = DeriveSha(receipts) - self.header.Bloom = CreateBloom(receipts) -} -func (self *Block) AddReceipt(receipt *Receipt) { - self.receipts = append(self.receipts, receipt) - self.SetReceipts(self.receipts) -} - -func (self *Block) RlpData() interface{} { - return []interface{}{self.header, self.transactions, self.uncles} -} +func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) } +func (b *Block) GasLimit() *big.Int { return new(big.Int).Set(b.header.GasLimit) } +func (b *Block) GasUsed() *big.Int { return new(big.Int).Set(b.header.GasUsed) } +func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) } -func (self *Block) RlpDataForStorage() interface{} { - return []interface{}{self.header, self.transactions, self.uncles, self.Td /* TODO receipts */} -} +func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() } +func (b *Block) MixDigest() common.Hash { return b.header.MixDigest } +func (b *Block) Nonce() uint64 { return binary.BigEndian.Uint64(b.header.Nonce[:]) } +func (b *Block) Bloom() Bloom { return b.header.Bloom } +func (b *Block) Coinbase() common.Address { return b.header.Coinbase } +func (b *Block) Time() int64 { return int64(b.header.Time) } +func (b *Block) Root() common.Hash { return b.header.Root } +func (b *Block) ParentHash() common.Hash { return b.header.ParentHash } +func (b *Block) TxHash() common.Hash { return b.header.TxHash } +func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash } +func (b *Block) UncleHash() common.Hash { return b.header.UncleHash } +func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) } -// Header accessors (add as you need them) -func (self *Block) Number() *big.Int { return self.header.Number } -func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() } -func (self *Block) MixDigest() common.Hash { return self.header.MixDigest } -func (self *Block) Nonce() uint64 { - return binary.BigEndian.Uint64(self.header.Nonce[:]) -} -func (self *Block) SetNonce(nonce uint64) { - self.header.SetNonce(nonce) -} +func (b *Block) Header() *Header { return copyHeader(b.header) } -func (self *Block) Queued() bool { return self.queued } -func (self *Block) SetQueued(q bool) { self.queued = q } - -func (self *Block) Bloom() Bloom { return self.header.Bloom } -func (self *Block) Coinbase() common.Address { return self.header.Coinbase } -func (self *Block) Time() int64 { return int64(self.header.Time) } -func (self *Block) GasLimit() *big.Int { return self.header.GasLimit } -func (self *Block) GasUsed() *big.Int { return self.header.GasUsed } -func (self *Block) Root() common.Hash { return self.header.Root } -func (self *Block) SetRoot(root common.Hash) { self.header.Root = root } -func (self *Block) GetTransaction(i int) *Transaction { - if len(self.transactions) > i { - return self.transactions[i] - } - return nil -} -func (self *Block) GetUncle(i int) *Header { - if len(self.uncles) > i { - return self.uncles[i] - } - return nil +func (b *Block) HashNoNonce() common.Hash { + return b.header.HashNoNonce() } -func (self *Block) Size() common.StorageSize { +func (b *Block) Size() common.StorageSize { c := writeCounter(0) - rlp.Encode(&c, self) + rlp.Encode(&c, b) return common.StorageSize(c) } @@ -335,48 +307,32 @@ func (c *writeCounter) Write(b []byte) (int, error) { return len(b), nil } -// Implement pow.Block -func (self *Block) Difficulty() *big.Int { return self.header.Difficulty } -func (self *Block) HashNoNonce() common.Hash { return self.header.HashNoNonce() } - -func (self *Block) Hash() common.Hash { - if (self.HeaderHash != common.Hash{}) { - return self.HeaderHash - } else { - return self.header.Hash() - } +func CalcUncleHash(uncles []*Header) common.Hash { + return rlpHash(uncles) } -func (self *Block) ParentHash() common.Hash { - if (self.ParentHeaderHash != common.Hash{}) { - return self.ParentHeaderHash - } else { - return self.header.ParentHash +// WithMiningResult returns a new block with the data from b +// where nonce and mix digest are set to the provided values. +func (b *Block) WithMiningResult(nonce uint64, mixDigest common.Hash) *Block { + cpy := *b.header + binary.BigEndian.PutUint64(cpy.Nonce[:], nonce) + cpy.MixDigest = mixDigest + return &Block{ + header: &cpy, + transactions: b.transactions, + receipts: b.receipts, + uncles: b.uncles, + Td: b.Td, } } -func (self *Block) Copy() *Block { - block := NewBlock(self.header.ParentHash, self.Coinbase(), self.Root(), new(big.Int), self.Nonce(), self.header.Extra) - block.header.Bloom = self.header.Bloom - block.header.TxHash = self.header.TxHash - block.transactions = self.transactions - block.header.UncleHash = self.header.UncleHash - block.uncles = self.uncles - block.header.GasLimit.Set(self.header.GasLimit) - block.header.GasUsed.Set(self.header.GasUsed) - block.header.ReceiptHash = self.header.ReceiptHash - block.header.Difficulty.Set(self.header.Difficulty) - block.header.Number.Set(self.header.Number) - block.header.Time = self.header.Time - block.header.MixDigest = self.header.MixDigest - if self.Td != nil { - block.Td.Set(self.Td) - } +// Implement pow.Block - return block +func (b *Block) Hash() common.Hash { + return b.header.Hash() } -func (self *Block) String() string { +func (b *Block) String() string { str := fmt.Sprintf(`Block(#%v): Size: %v TD: %v { MinerHash: %x %v @@ -385,20 +341,11 @@ Transactions: Uncles: %v } -`, self.Number(), self.Size(), self.Td, self.header.HashNoNonce(), self.header, self.transactions, self.uncles) - - if (self.HeaderHash != common.Hash{}) { - str += fmt.Sprintf("\nFake hash = %x", self.HeaderHash) - } - - if (self.ParentHeaderHash != common.Hash{}) { - str += fmt.Sprintf("\nFake parent hash = %x", self.ParentHeaderHash) - } - +`, b.Number(), b.Size(), b.Td, b.header.HashNoNonce(), b.header, b.transactions, b.uncles) return str } -func (self *Header) String() string { +func (h *Header) String() string { return fmt.Sprintf(`Header(%x): [ ParentHash: %x @@ -414,9 +361,9 @@ func (self *Header) String() string { GasUsed: %v Time: %v Extra: %s - MixDigest: %x + MixDigest: %x Nonce: %x -]`, self.Hash(), self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.MixDigest, self.Nonce) +]`, h.Hash(), h.ParentHash, h.UncleHash, h.Coinbase, h.Root, h.TxHash, h.ReceiptHash, h.Bloom, h.Difficulty, h.Number, h.GasLimit, h.GasUsed, h.Time, h.Extra, h.MixDigest, h.Nonce) } type Blocks []*Block @@ -442,4 +389,4 @@ func (self blockSorter) Swap(i, j int) { } func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } -func Number(b1, b2 *Block) bool { return b1.Header().Number.Cmp(b2.Header().Number) < 0 } +func Number(b1, b2 *Block) bool { return b1.header.Number.Cmp(b2.header.Number) < 0 } |