diff --git a/cmd/geth/main.go b/cmd/geth/main.go index aacb588feb..3c2f37a233 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -536,7 +536,7 @@ func blockRecovery(ctx *cli.Context) { glog.Fatalln("block not found. Recovery failed") } - err = core.WriteHead(blockDb, block) + err = core.WriteHeadBlockMeta(blockDb, block) if err != nil { glog.Fatalln("block write err", err) } diff --git a/core/bench_test.go b/core/bench_test.go index baae8a7a5e..cd36ee76a7 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -133,12 +133,12 @@ func genTxRing(naccounts int) func(int, *BlockGen) { // genUncles generates blocks with two uncle headers. func genUncles(i int, gen *BlockGen) { if i >= 6 { - b2 := gen.PrevBlock(i - 6).Header() + b2 := gen.PrevBlock(i - 6).Header().Raw() b2.Extra = []byte("foo") - gen.AddUncle(b2) - b3 := gen.PrevBlock(i - 6).Header() + gen.AddUncle(types.NewHeader(b2)) + b3 := gen.PrevBlock(i - 6).Header().Raw() b3.Extra = []byte("bar") - gen.AddUncle(b3) + gen.AddUncle(types.NewHeader(b3)) } } diff --git a/core/block_cache_test.go b/core/block_cache_test.go index ef826d5bda..5a08572785 100644 --- a/core/block_cache_test.go +++ b/core/block_cache_test.go @@ -27,8 +27,11 @@ import ( func newChain(size int) (chain []*types.Block) { var parentHash common.Hash for i := 0; i < size; i++ { - head := &types.Header{ParentHash: parentHash, Number: big.NewInt(int64(i))} - block := types.NewBlock(head, nil, nil, nil) + header := &types.RawHeader{ + ParentHash: parentHash, + Number: big.NewInt(int64(i)), + } + block := types.NewBlock(header, nil, nil, nil) chain = append(chain, block) parentHash = block.Hash() } diff --git a/core/block_processor.go b/core/block_processor.go index 1238fda7b9..9819126a8b 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -230,7 +230,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. rbloom := types.CreateBloom(receipts) - if rbloom != header.Bloom { + if rbloom != header.Bloom() { err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom) return } @@ -238,21 +238,21 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st // The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]])) // can be used by light clients to make sure they've received the correct Txs txSha := types.DeriveSha(txs) - if txSha != header.TxHash { + if txSha != header.TxHash() { err = fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha) return } // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]])) receiptSha := types.DeriveSha(receipts) - if receiptSha != header.ReceiptHash { + if receiptSha != header.ReceiptHash() { err = fmt.Errorf("invalid receipt root hash. received=%x calculated=%x", header.ReceiptHash, receiptSha) return } // Verify UncleHash before running other uncle validations unclesSha := types.CalcUncleHash(uncles) - if unclesSha != header.UncleHash { + if unclesSha != header.UncleHash() { err = fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha) return } @@ -267,7 +267,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st // Commit state objects/accounts to a temporary trie (does not save) // used to calculate the state root. state.SyncObjects() - if header.Root != state.Root() { + if header.Root() != state.Root() { err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root()) return } @@ -291,16 +291,16 @@ func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*t reward := new(big.Int).Set(BlockReward) r := new(big.Int) for _, uncle := range uncles { - r.Add(uncle.Number, big8) - r.Sub(r, header.Number) + r.Add(uncle.Number(), big8) + r.Sub(r, header.Number()) r.Mul(r, BlockReward) r.Div(r, big8) - statedb.AddBalance(uncle.Coinbase, r) + statedb.AddBalance(uncle.Coinbase(), r) r.Div(BlockReward, big32) reward.Add(reward, r) } - statedb.AddBalance(header.Coinbase, reward) + statedb.AddBalance(header.Coinbase(), reward) } func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *types.Block) error { @@ -333,11 +333,11 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty return UncleError("uncle[%d](%x) is ancestor", i, hash[:4]) } - if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == parent.Hash() { - return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4]) + if uncleParent := uncle.ParentHash(); ancestors[uncleParent] == nil || uncleParent == parent.Hash() { + return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncleParent[:4]) } - if err := ValidateHeader(sm.Pow, uncle, ancestors[uncle.ParentHash], true, true); err != nil { + if err := ValidateHeader(sm.Pow, uncle, ancestors[uncle.ParentHash()], true, true); err != nil { return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err)) } } @@ -368,49 +368,49 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro // See YP section 4.3.4. "Block Header Validity" // Validates a block. Returns an error if the block is invalid. -func ValidateHeader(pow pow.PoW, block *types.Header, parent *types.Block, checkPow, uncle bool) error { - if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 { - return fmt.Errorf("Block extra data too long (%d)", len(block.Extra)) +func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Block, checkPow, uncle bool) error { + if big.NewInt(int64(len(header.Extra()))).Cmp(params.MaximumExtraDataSize) == 1 { + return fmt.Errorf("Header extra data too long (%d)", len(header.Extra())) } if uncle { - if block.Time.Cmp(common.MaxBig) == 1 { + if header.Time().Cmp(common.MaxBig) == 1 { return BlockTSTooBigErr } } else { - if block.Time.Cmp(big.NewInt(time.Now().Unix())) == 1 { + if header.Time().Cmp(big.NewInt(time.Now().Unix())) == 1 { return BlockFutureErr } } - if block.Time.Cmp(parent.Time()) != 1 { + if header.Time().Cmp(parent.Time()) != 1 { return BlockEqualTSErr } - expd := CalcDifficulty(block.Time.Uint64(), parent.Time().Uint64(), parent.Number(), parent.Difficulty()) - if expd.Cmp(block.Difficulty) != 0 { - return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) + expd := CalcDifficulty(header.Time().Uint64(), parent.Time().Uint64(), parent.Number(), parent.Difficulty()) + if expd.Cmp(header.Difficulty()) != 0 { + return fmt.Errorf("Difficulty check failed for header %v, %v", header.Difficulty(), expd) } var a, b *big.Int a = parent.GasLimit() - a = a.Sub(a, block.GasLimit) + a = a.Sub(a, header.GasLimit()) a.Abs(a) b = parent.GasLimit() b = b.Div(b, params.GasLimitBoundDivisor) - if !(a.Cmp(b) < 0) || (block.GasLimit.Cmp(params.MinGasLimit) == -1) { - return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b) + if !(a.Cmp(b) < 0) || (header.GasLimit().Cmp(params.MinGasLimit) == -1) { + return fmt.Errorf("GasLimit check failed for header %v (%v > %v)", header.GasLimit(), a, b) } num := parent.Number() - num.Sub(block.Number, num) + num.Sub(header.Number(), num) if num.Cmp(big.NewInt(1)) != 0 { return BlockNumberErr } if checkPow { - // Verify the nonce of the block. Return an error if it's not valid - if !pow.Verify(types.NewBlockWithHeader(block)) { - return ValidationError("Block's nonce is invalid (= %x)", block.Nonce) + // Verify the nonce of the header. Return an error if it's not valid + if !pow.Verify(types.NewBlockWithHeader(header)) { + return ValidationError("Block's nonce is invalid (= %x)", header.Nonce()) } } diff --git a/core/block_processor_test.go b/core/block_processor_test.go index e0b2d3313f..580129a247 100644 --- a/core/block_processor_test.go +++ b/core/block_processor_test.go @@ -48,13 +48,13 @@ func TestNumber(t *testing.T) { statedb := state.New(chain.Genesis().Root(), chain.chainDb) header := makeHeader(chain.Genesis(), statedb) header.Number = big.NewInt(3) - err := ValidateHeader(pow, header, chain.Genesis(), false, false) + err := ValidateHeader(pow, types.NewHeader(header), chain.Genesis(), false, false) if err != BlockNumberErr { t.Errorf("expected block number error, got %q", err) } header = makeHeader(chain.Genesis(), statedb) - err = ValidateHeader(pow, header, chain.Genesis(), false, false) + err = ValidateHeader(pow, types.NewHeader(header), chain.Genesis(), false, false) if err == BlockNumberErr { t.Errorf("didn't expect block number error") } diff --git a/core/chain_makers.go b/core/chain_makers.go index b009e0c28c..20d0511a96 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -49,7 +49,7 @@ type BlockGen struct { i int parent *types.Block chain []*types.Block - header *types.Header + header *types.RawHeader statedb *state.StateDB coinbase *state.StateObject @@ -89,12 +89,12 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { if b.coinbase == nil { b.SetCoinbase(common.Address{}) } - _, gas, err := ApplyMessage(NewEnv(b.statedb, nil, tx, b.header), tx, b.coinbase) + _, gas, err := ApplyMessage(NewEnv(b.statedb, nil, tx, types.NewHeader(b.header)), tx, b.coinbase) if err != nil { panic(err) } b.statedb.SyncIntermediate() - b.header.GasUsed.Add(b.header.GasUsed, gas) + b.header.GasUsed = new(big.Int).Add(b.header.GasUsed, gas) receipt := types.NewReceipt(b.statedb.Root().Bytes(), b.header.GasUsed) logs := b.statedb.GetLogs(tx.Hash()) receipt.SetLogs(logs) @@ -145,12 +145,12 @@ func (b *BlockGen) PrevBlock(index int) *types.Block { func GenerateChain(parent *types.Block, db common.Database, n int, gen func(int, *BlockGen)) []*types.Block { statedb := state.New(parent.Root(), db) blocks := make(types.Blocks, n) - genblock := func(i int, h *types.Header) *types.Block { + genblock := func(i int, h *types.RawHeader) *types.Block { b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb} if gen != nil { gen(i, b) } - AccumulateRewards(statedb, h, b.uncles) + AccumulateRewards(statedb, types.NewHeader(h), b.uncles) statedb.SyncIntermediate() h.Root = statedb.Root() return types.NewBlock(h, b.txs, b.uncles, b.receipts) @@ -165,14 +165,14 @@ func GenerateChain(parent *types.Block, db common.Database, n int, gen func(int, return blocks } -func makeHeader(parent *types.Block, state *state.StateDB) *types.Header { +func makeHeader(parent *types.Block, state *state.StateDB) *types.RawHeader { var time *big.Int if parent.Time() == nil { time = big.NewInt(10) } else { time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds } - return &types.Header{ + return &types.RawHeader{ Root: state.Root(), ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 1c868624df..31e3ff29a4 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -66,12 +66,12 @@ func ExampleGenerateChain() { gen.SetExtra([]byte("yeehaw")) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). - b2 := gen.PrevBlock(1).Header() + b2 := gen.PrevBlock(1).Header().Raw() b2.Extra = []byte("foo") - gen.AddUncle(b2) - b3 := gen.PrevBlock(2).Header() + gen.AddUncle(types.NewHeader(b2)) + b3 := gen.PrevBlock(2).Header().Raw() b3.Extra = []byte("foo") - gen.AddUncle(b3) + gen.AddUncle(types.NewHeader(b3)) } }) diff --git a/core/chain_manager.go b/core/chain_manager.go index 745b270f7c..381d009f99 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -207,7 +207,7 @@ func (bc *ChainManager) recover() bool { if len(data) != 0 { block := bc.GetBlock(common.BytesToHash(data)) if block != nil { - if err := WriteHead(bc.chainDb, block); err != nil { + if err := WriteHeadBlockMeta(bc.chainDb, block); err != nil { glog.Fatalf("failed to write database head: %v", err) } bc.currentBlock = block @@ -219,7 +219,7 @@ func (bc *ChainManager) recover() bool { } func (bc *ChainManager) setLastState() error { - head := GetHeadHash(bc.chainDb) + head := GetHeadBlockHash(bc.chainDb) if head != (common.Hash{}) { block := bc.GetBlock(head) if block != nil { @@ -315,7 +315,7 @@ func (self *ChainManager) ExportN(w io.Writer, first uint64, last uint64) error // insert injects a block into the current chain block chain. Note, this function // assumes that the `mu` mutex is held! func (bc *ChainManager) insert(block *types.Block) { - err := WriteHead(bc.chainDb, block) + err := WriteHeadBlockMeta(bc.chainDb, block) if err != nil { glog.Fatal("db write fail:", err) } @@ -451,11 +451,11 @@ func (self *ChainManager) GetBlockHashesFromHash(hash common.Hash, max uint64) [ // Iterate the headers until enough is collected or the genesis reached chain := make([]common.Hash, 0, max) for i := uint64(0); i < max; i++ { - if header = self.GetHeader(header.ParentHash); header == nil { + if header = self.GetHeader(header.ParentHash()); header == nil { break } chain = append(chain, header.Hash()) - if header.Number.Cmp(common.Big0) <= 0 { + if header.Number().Cmp(common.Big0) <= 0 { break } } @@ -531,6 +531,22 @@ const ( SideStatTy ) +/* +// WriteHeader inserts a potentially new header into the database, updating the +// head-header-hash index too if greater than the previous. +func (self *ChainManager) WriteHeader(db common.Database, header *types.Header) error { + self.wg.Add(1) + defer self.wg.Done() + + // Store the header into the database + if err := WriteHeader(self.chainDb, header); err != nil { + glog.Fatalf("failed to write header: %v", err) + return err + } + // If the header's higher than our previous head, update + if header. +}*/ + // WriteBlock writes the block to the chain (or pending queue) func (self *ChainManager) WriteBlock(block *types.Block, queued bool) (status writeStatus, err error) { self.wg.Add(1) diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index 97e7cacdc9..8692bb97a2 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -369,7 +369,7 @@ func (bproc) Process(*types.Block) (state.Logs, types.Receipts, error) { return func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block { var chain []*types.Block for i, difficulty := range d { - header := &types.Header{ + header := &types.RawHeader{ Coinbase: common.Address{seed}, Number: big.NewInt(int64(i + 1)), Difficulty: big.NewInt(int64(difficulty)), @@ -379,7 +379,7 @@ func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block } else { header.ParentHash = chain[i-1].Hash() } - block := types.NewBlockWithHeader(header) + block := types.NewBlockWithRawHeader(header) chain = append(chain, block) } return chain diff --git a/core/chain_util.go b/core/chain_util.go index c12bdda75d..185e04a135 100644 --- a/core/chain_util.go +++ b/core/chain_util.go @@ -29,7 +29,8 @@ import ( ) var ( - headKey = []byte("LastBlock") + headHeaderKey = []byte("LastHeader") + headBlockKey = []byte("LastBlock") headerHashPre = []byte("header-hash-") bodyHashPre = []byte("body-hash-") @@ -131,9 +132,22 @@ func GetHashByNumber(db common.Database, number uint64) common.Hash { return common.BytesToHash(data) } -// GetHeadHash retrieves the hash of the current canonical head block. -func GetHeadHash(db common.Database) common.Hash { - data, _ := db.Get(headKey) +// GetHeadHeaderHash retrieves the hash of the current canonical head block's +// header. The different between this and GetHeadBlockHash is that whereas the +// last block hash is only updated upon a full block import, the last header +// hash is updated already at header import, allowing head tracking for the +// fast synchronization mechanism. +func GetHeadHeaderHash(db common.Database) common.Hash { + data, _ := db.Get(headHeaderKey) + if len(data) == 0 { + return common.Hash{} + } + return common.BytesToHash(data) +} + +// GetHeadBlockHash retrieves the hash of the current canonical head block. +func GetHeadBlockHash(db common.Database) common.Hash { + data, _ := db.Get(headBlockKey) if len(data) == 0 { return common.Hash{} } @@ -232,14 +246,23 @@ func WriteCanonNumber(db common.Database, hash common.Hash, number uint64) error return nil } -// WriteHead updates the head block of the chain database. -func WriteHead(db common.Database, block *types.Block) error { - if err := WriteCanonNumber(db, block.Hash(), block.NumberU64()); err != nil { - glog.Fatalf("failed to store canonical number into database: %v", err) +// WriteHeadBlockMeta stores the head header's hash. +func WriteHeadHeaderHash(db common.Database, header *types.Header) error { + if err := db.Put(headHeaderKey, header.Hash().Bytes()); err != nil { + glog.Fatalf("failed to store last header's hash into database: %v", err) return err } - if err := db.Put(headKey, block.Hash().Bytes()); err != nil { - glog.Fatalf("failed to store last block into database: %v", err) + return nil +} + +// WriteHeadBlockMeta stores the head block's metadata (number and hash). +func WriteHeadBlockMeta(db common.Database, block *types.Block) error { + if err := WriteCanonNumber(db, block.Hash(), block.NumberU64()); err != nil { + glog.Fatalf("failed to store last block's canonical number into database: %v", err) + return err + } + if err := db.Put(headBlockKey, block.Hash().Bytes()); err != nil { + glog.Fatalf("failed to store last block's hash into database: %v", err) return err } return nil diff --git a/core/genesis.go b/core/genesis.go index 6fbc671b06..5ba09e477b 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -71,7 +71,8 @@ func WriteGenesisBlock(chainDb common.Database, reader io.Reader) (*types.Block, statedb.SyncObjects() difficulty := common.String2Big(genesis.Difficulty) - block := types.NewBlock(&types.Header{ + + header := &types.RawHeader{ Nonce: types.EncodeNonce(common.String2Big(genesis.Nonce).Uint64()), Time: common.String2Big(genesis.Timestamp), ParentHash: common.HexToHash(genesis.ParentHash), @@ -81,7 +82,8 @@ func WriteGenesisBlock(chainDb common.Database, reader io.Reader) (*types.Block, MixDigest: common.HexToHash(genesis.Mixhash), Coinbase: common.HexToAddress(genesis.Coinbase), Root: statedb.Root(), - }, nil, nil, nil) + } + block := types.NewBlock(header, nil, nil, nil) block.Td = difficulty if block := GetBlockByHash(chainDb, block.Hash()); block != nil { @@ -99,7 +101,7 @@ func WriteGenesisBlock(chainDb common.Database, reader io.Reader) (*types.Block, if err != nil { return nil, err } - err = WriteHead(chainDb, block) + err = WriteHeadBlockMeta(chainDb, block) if err != nil { return nil, err } @@ -115,11 +117,13 @@ func GenesisBlockForTesting(db common.Database, addr common.Address, balance *bi obj.SetBalance(balance) statedb.SyncObjects() statedb.Sync() - block := types.NewBlock(&types.Header{ + + header := &types.RawHeader{ Difficulty: params.GenesisDifficulty, GasLimit: params.GenesisGasLimit, Root: statedb.Root(), - }, nil, nil, nil) + } + block := types.NewBlock(header, nil, nil, nil) block.Td = params.GenesisDifficulty return block } diff --git a/core/types/block.go b/core/types/block.go index 558b46e010..6dd3718820 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -18,9 +18,6 @@ package types import ( - "bytes" - "encoding/binary" - "encoding/json" "fmt" "io" "math/big" @@ -29,94 +26,11 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/rlp" ) -// 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 EncodeNonce(i uint64) BlockNonce { - var n BlockNonce - binary.BigEndian.PutUint64(n[:], i) - return n -} - -func (n BlockNonce) Uint64() uint64 { - return binary.BigEndian.Uint64(n[:]) -} - -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 *big.Int // 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 { - var ext struct { - ParentHash string - Coinbase string - Difficulty string - GasLimit string - Time *big.Int - Extra string - } - dec := json.NewDecoder(bytes.NewReader(data)) - if err := dec.Decode(&ext); err != nil { - return err - } - - h.ParentHash = common.HexToHash(ext.ParentHash) - h.Coinbase = common.HexToAddress(ext.Coinbase) - h.Difficulty = common.String2Big(ext.Difficulty) - h.Time = ext.Time - h.Extra = []byte(ext.Extra) - return nil -} - -func rlpHash(x interface{}) (h common.Hash) { - hw := sha3.NewKeccak256() - rlp.Encode(hw, x) - hw.Sum(h[:0]) - return h -} - +// Header is the main Ethereum block, containing all of the block data belonging +// to the consensus protocol, as well as a few added fields for the implementation. type Block struct { header *Header uncles []*Header @@ -124,7 +38,6 @@ type Block struct { receipts Receipts // caches - hash atomic.Value size atomic.Value // Td is used by package core to store the total difficulty @@ -169,69 +82,56 @@ var ( // 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)} +func NewBlock(header *RawHeader, txs []*Transaction, uncles []*Header, receipts []*Receipt) *Block { + head := header.Copy() // TODO: panic if len(txs) != len(receipts) if len(txs) == 0 { - b.header.TxHash = emptyRootHash + head.TxHash = emptyRootHash } else { - b.header.TxHash = DeriveSha(Transactions(txs)) - b.transactions = make(Transactions, len(txs)) - copy(b.transactions, txs) + head.TxHash = DeriveSha(Transactions(txs)) } + txsCopy := make(Transactions, len(txs)) + copy(txsCopy, txs) if len(receipts) == 0 { - b.header.ReceiptHash = emptyRootHash + head.ReceiptHash = emptyRootHash } else { - b.header.ReceiptHash = DeriveSha(Receipts(receipts)) - b.header.Bloom = CreateBloom(receipts) - b.receipts = make([]*Receipt, len(receipts)) - copy(b.receipts, receipts) + head.ReceiptHash = DeriveSha(Receipts(receipts)) + head.Bloom = CreateBloom(receipts) } + receiptsCopy := make([]*Receipt, len(receipts)) + copy(receiptsCopy, receipts) if len(uncles) == 0 { - b.header.UncleHash = emptyUncleHash + head.UncleHash = emptyUncleHash } else { - b.header.UncleHash = CalcUncleHash(uncles) - b.uncles = make([]*Header, len(uncles)) - for i := range uncles { - b.uncles[i] = copyHeader(uncles[i]) - } + head.UncleHash = CalcUncleHash(uncles) + } + unclesCopy := make([]*Header, len(uncles)) + for i := range uncles { + unclesCopy[i] = uncles[i].Copy() + } + // Assemble and return an immutable block + return &Block{ + header: &Header{rawHeader: *head}, + transactions: txsCopy, + receipts: receiptsCopy, + uncles: unclesCopy, + Td: new(big.Int), } - - 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. +// NewBlockWithRawHeader 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 NewBlockWithRawHeader(raw *RawHeader) *Block { + return &Block{header: NewHeader(raw)} +} + +// NewBlockWithHeader creates a block with the given immutable header. func NewBlockWithHeader(header *Header) *Block { - return &Block{header: copyHeader(header)} -} - -func copyHeader(h *Header) *Header { - cpy := *h - if cpy.Time = new(big.Int); h.Time != nil { - cpy.Time.Set(h.Time) - } - 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 + return &Block{header: header} } func (b *Block) ValidateFields() error { @@ -304,29 +204,28 @@ func (b *Block) Transaction(hash common.Hash) *Transaction { return nil } -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 (b *Block) Time() *big.Int { return new(big.Int).Set(b.header.Time) } +func (b *Block) Number() *big.Int { return b.header.Number() } +func (b *Block) GasLimit() *big.Int { return b.header.GasLimit() } +func (b *Block) GasUsed() *big.Int { return b.header.GasUsed() } +func (b *Block) Difficulty() *big.Int { return b.header.Difficulty() } +func (b *Block) Time() *big.Int { return b.header.Time() } -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) 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) } +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 b.header.Nonce().Uint64() } +func (b *Block) Bloom() Bloom { return b.header.Bloom() } +func (b *Block) Coinbase() common.Address { return b.header.Coinbase() } +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 b.header.Extra() } -func (b *Block) Header() *Header { return copyHeader(b.header) } +func (b *Block) Header() *Header { return b.header } -func (b *Block) HashNoNonce() common.Hash { - return b.header.HashNoNonce() -} +func (b *Block) HashNoNonce() common.Hash { return b.header.HashNoNonce() } +func (b *Block) Hash() common.Hash { return b.header.Hash() } func (b *Block) Size() common.StorageSize { if size := b.size.Load(); size != nil { @@ -352,11 +251,11 @@ func CalcUncleHash(uncles []*Header) common.Hash { // 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 + header := b.header.Raw() + header.Nonce = EncodeNonce(nonce) + header.MixDigest = mixDigest return &Block{ - header: &cpy, + header: &Header{rawHeader: *header}, transactions: b.transactions, receipts: b.receipts, uncles: b.uncles, @@ -367,28 +266,19 @@ func (b *Block) WithMiningResult(nonce uint64, mixDigest common.Hash) *Block { // WithBody returns a new block with the given transaction and uncle contents. func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block { block := &Block{ - header: copyHeader(b.header), + header: b.header.Copy(), transactions: make([]*Transaction, len(transactions)), uncles: make([]*Header, len(uncles)), } copy(block.transactions, transactions) for i := range uncles { - block.uncles[i] = copyHeader(uncles[i]) + block.uncles[i] = uncles[i].Copy() } return block } // Implement pow.Block -func (b *Block) Hash() common.Hash { - if hash := b.hash.Load(); hash != nil { - return hash.(common.Hash) - } - v := rlpHash(b.header) - b.hash.Store(v) - return v -} - func (b *Block) String() string { str := fmt.Sprintf(`Block(#%v): Size: %v TD: %v { MinerHash: %x @@ -402,27 +292,6 @@ Uncles: return str } -func (h *Header) String() string { - return fmt.Sprintf(`Header(%x): -[ - ParentHash: %x - UncleHash: %x - Coinbase: %x - Root: %x - TxSha %x - ReceiptSha: %x - Bloom: %x - Difficulty: %v - Number: %v - GasLimit: %v - GasUsed: %v - Time: %v - Extra: %s - MixDigest: %x - Nonce: %x -]`, 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 type BlockBy func(b1, b2 *Block) bool @@ -446,4 +315,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 } diff --git a/core/types/header.go b/core/types/header.go new file mode 100644 index 0000000000..2dddeadd58 --- /dev/null +++ b/core/types/header.go @@ -0,0 +1,309 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Contains the block header type and related methods. + +package types + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "io" + "math/big" + "sync/atomic" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/sha3" + "github.com/ethereum/go-ethereum/rlp" +) + +// 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 EncodeNonce(i uint64) BlockNonce { + var n BlockNonce + binary.BigEndian.PutUint64(n[:], i) + return n +} + +func (n BlockNonce) Uint64() uint64 { + return binary.BigEndian.Uint64(n[:]) +} + +// RawHeader is the base consensus header used by the Ethereum system, which +// contains only the bare essential fields defined by the consensus protocol. +// +// This structure is mutable, and can be used to create an immutable header +// used throughout the codebase. Do not pass this structure around, only use +// to aid in new header construction or data query from an existing header. +type RawHeader struct { + ParentHash common.Hash // Hash of the previous block in the chain + UncleHash common.Hash // Hash of the uncles contained in this block + Coinbase common.Address // Owner address of the block (miner) + Root common.Hash // Merkle-Patricia state trie root hash + TxHash common.Hash // Hash of the transactions contained in this block + ReceiptHash common.Hash // Hash of the transactions receipts contained in this block + Bloom Bloom // Bloom filter for the event logs in the block + Difficulty *big.Int // Proof-of-work difficulty of this block + Number *big.Int // Index number of the block within the chain + GasLimit *big.Int // Maximum gas allowance for this block + GasUsed *big.Int // Amount of gas actually used in this block + Time *big.Int // Creation timestamp of this block + Extra []byte // Extra data inserted into the block by the miner + MixDigest common.Hash // Miner mix digest for quick difficulty verification + Nonce BlockNonce // Proof-of-work nonce of the block +} + +// hash calculates the nonce-inclusive hash of the header. As the raw header is +// mutable, this hasher cannot cache its expensive operation, hence it's private +// and users are required to use the immutable Header's Hash method. +func (h *RawHeader) hash() common.Hash { + return rlpHash(h) +} + +// hashNoNonce calculates the miner hash of the header (no mix digest or nonce). +// Similarly to the hash method, as the raw header is mutable, this hasher also +// cannot cache its expensive operation, hence it's private and users are asked +// to use the immutable Header's HashNoNonce method. +func (h *RawHeader) 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, + }) +} + +// Copy creates a deep copy of a raw header. +func (h *RawHeader) Copy() *RawHeader { + 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 cpy.Time = new(big.Int); h.Time != nil { + cpy.Time.Set(h.Time) + } + if len(h.Extra) > 0 { + cpy.Extra = common.CopyBytes(h.Extra) + } + return &cpy +} + +// Header is the immutable Ethereum block header, containing all of the metadata +// related to a chain block, and some additional helper fields, caches. +type Header struct { + rawHeader RawHeader // Base header fields part of the consensus protocol + + hashNoNonce atomic.Value // Cached hash of the header without the nonce + hashWithNonce atomic.Value // Cached hash of the header with the nonce + rlpSize atomic.Value // Size of the header in RLP encoded format +} + +// NewHeader creates an immutable header from a mutable raw header. +func NewHeader(raw *RawHeader) *Header { + return &Header{ + rawHeader: *raw.Copy(), + } +} + +// Raw creates and returns a mutable deep copy of the raw consensus header. +func (h *Header) Raw() *RawHeader { + return h.rawHeader.Copy() +} + +// ParentHash retrieves the hash of this block's parent in the blockchain. +func (h *Header) ParentHash() common.Hash { return h.rawHeader.ParentHash } + +// UncleHash retrieves the hash of the uncle blocks contained within this block. +func (h *Header) UncleHash() common.Hash { return h.rawHeader.UncleHash } + +// Coinbase retrieves the account owning this block (i.e. miner). +func (h *Header) Coinbase() common.Address { return h.rawHeader.Coinbase } + +// Root retrieves the root hash of the Merkle-Patricia state trie formed. +func (h *Header) Root() common.Hash { return h.rawHeader.Root } + +// TxHash retrieves the hash of the transactions contained within this block. +func (h *Header) TxHash() common.Hash { return h.rawHeader.TxHash } + +// ReceiptHash retrieves the hash of the transaction receipts contained within. +func (h *Header) ReceiptHash() common.Hash { return h.rawHeader.ReceiptHash } + +// Bloom retrieves the bloom filter of the event logs contained within. +func (h *Header) Bloom() Bloom { return h.rawHeader.Bloom } + +// Difficulty retrieves the proof-of-work difficulty of this block. +func (h *Header) Difficulty() *big.Int { return new(big.Int).Set(h.rawHeader.Difficulty) } + +// Number retrieves the index/number of the block within the chain. +func (h *Header) Number() *big.Int { return new(big.Int).Set(h.rawHeader.Number) } + +// GasLimit retrieves the maximum gas allowance for this block. +func (h *Header) GasLimit() *big.Int { return new(big.Int).Set(h.rawHeader.GasLimit) } + +// GasUsed retrieves the amount of gas actually used in this block. +func (h *Header) GasUsed() *big.Int { return new(big.Int).Set(h.rawHeader.GasUsed) } + +// Time retrieves the creation timestamp of this block. +func (h *Header) Time() *big.Int { return new(big.Int).Set(h.rawHeader.Time) } + +// Extra retrieves the extra data inserted into the block by the miner. +func (h *Header) Extra() []byte { + return common.CopyBytes(h.rawHeader.Extra) +} + +// MixDigest retrieves the miner mix digest for quick difficulty verification. +func (h *Header) MixDigest() common.Hash { return h.rawHeader.MixDigest } + +// Nonce retrieves the proof-of-work nonce of the block. +func (h *Header) Nonce() BlockNonce { return h.rawHeader.Nonce } + +// RlpSize retrieves the RLP encoded size of the header, calculating and caching +// if it unknown. +func (h *Header) RlpSize() common.StorageSize { + if size := h.rlpSize.Load(); size != nil && size.(common.StorageSize).Int64() != 0 { + return size.(common.StorageSize) + } + counter := writeCounter(0) + rlp.Encode(&counter, h.rawHeader) + + h.rlpSize.Store(common.StorageSize(counter)) + return common.StorageSize(counter) +} + +// Hash retrieves the nonce-inclusive hash of the header, calculating and caching +// it if unknown. +func (h *Header) Hash() common.Hash { + if hash := h.hashWithNonce.Load(); hash != nil && hash.(common.Hash) != (common.Hash{}) { + return hash.(common.Hash) + } + hash := h.rawHeader.hash() + h.hashWithNonce.Store(hash) + return hash +} + +// HashNoNonce retrieves the miner hash of the header (no mix digest or nonce), +// calculating and caching it if unknown. +func (h *Header) HashNoNonce() common.Hash { + if hash := h.hashNoNonce.Load(); hash != nil && hash.(common.Hash) != (common.Hash{}) { + return hash.(common.Hash) + } + hash := h.rawHeader.hashNoNonce() + h.hashNoNonce.Store(hash) + return hash +} + +// DecodeRLP implements the rlp.Decoder interface, deserializing a raw header +// from an RLP Data stream. +func (h *Header) DecodeRLP(s *rlp.Stream) error { + // Reset any previously cached fields + h.hashNoNonce.Store(common.Hash{}) + h.hashWithNonce.Store(common.Hash{}) + h.rlpSize.Store(common.StorageSize(0)) + + // Fill in the real RLP encoded size of the header + _, size, _ := s.Kind() + h.rlpSize.Store(common.StorageSize(rlp.ListSize(size))) + + // Decode the RLP encoded raw header + return s.Decode(&h.rawHeader) +} + +// EncodeRLP implements the rlp.Encoder interface, serializing a raw header into +// and RLP data stream. +func (h *Header) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, h.rawHeader) +} + +func (h *Header) UnmarshalJSON(data []byte) error { + var ext struct { + ParentHash string + Coinbase string + Difficulty string + GasLimit string + Time *big.Int + Extra string + } + dec := json.NewDecoder(bytes.NewReader(data)) + if err := dec.Decode(&ext); err != nil { + return err + } + h.rawHeader.ParentHash = common.HexToHash(ext.ParentHash) + h.rawHeader.Coinbase = common.HexToAddress(ext.Coinbase) + h.rawHeader.Difficulty = common.String2Big(ext.Difficulty) + h.rawHeader.Time = ext.Time + h.rawHeader.Extra = []byte(ext.Extra) + + return nil +} + +// Copy creates a deep copy of a header. +func (h *Header) Copy() *Header { + cpy := new(Header) + cpy.rawHeader = *h.rawHeader.Copy() + return cpy +} + +// String implements the fmt.Stringer interface, formatting a header into a string. +func (h *Header) String() string { + return fmt.Sprintf(`Header(%x): +[ + ParentHash: %x + UncleHash: %x + Coinbase: %x + Root: %x + TxSha: %x + ReceiptSha: %x + Bloom: %x + Difficulty: %v + Number: %v + GasLimit: %v + GasUsed: %v + Time: %v + Extra: %s + MixDigest: %x + Nonce: %x +]`, 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()) +} + +func rlpHash(x interface{}) (h common.Hash) { + hw := sha3.NewKeccak256() + rlp.Encode(hw, x) + hw.Sum(h[:0]) + return h +} diff --git a/core/vm_env.go b/core/vm_env.go index a08f024fe7..fb373ccc23 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -27,7 +27,7 @@ import ( type VMEnv struct { state *state.StateDB - header *types.Header + header *types.RawHeader msg Message depth int chain *ChainManager @@ -40,7 +40,7 @@ func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, header *type return &VMEnv{ chain: chain, state: state, - header: header, + header: header.Raw(), msg: msg, typ: vm.StdVmTy, } diff --git a/eth/backend.go b/eth/backend.go index 7bafcbc83e..d911ae6438 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -315,7 +315,7 @@ func New(config *Config) (*Ethereum, error) { // This is for testing only. if config.GenesisBlock != nil { core.WriteBlock(chainDb, config.GenesisBlock) - core.WriteHead(chainDb, config.GenesisBlock) + core.WriteHeadBlockMeta(chainDb, config.GenesisBlock) } if !config.SkipBcVersionCheck { diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 574f2ba15e..a593da0ed2 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -810,7 +810,7 @@ func (d *Downloader) findAncestor(p *peer) (uint64, error) { finished = true for i := len(headers) - 1; i >= 0; i-- { if d.hasBlock(headers[i].Hash()) { - number, hash = headers[i].Number.Uint64(), headers[i].Hash() + number, hash = headers[i].Number().Uint64(), headers[i].Hash() break } } diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 8d009b6717..0eccb1885e 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -58,7 +58,11 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common } // If the block number is a multiple of 5, add a bonus uncle to the block if i%5 == 0 { - block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))}) + uncle := &types.RawHeader{ + ParentHash: block.PrevBlock(i - 1).Hash(), + Number: big.NewInt(int64(i - 1)), + } + block.AddUncle(types.NewHeader(uncle)) } }) hashes := make([]common.Hash, n+1) @@ -696,7 +700,7 @@ func testBlockBodyAttackerDropping(t *testing.T, protocol int) { // Assemble a good or bad block, depending of the test raw := core.GenerateChain(genesis, testdb, 1, nil)[0] if tt.failure { - parent := types.NewBlock(&types.Header{}, nil, nil, nil) + parent := types.NewBlock(new(types.RawHeader), nil, nil, nil) raw = core.GenerateChain(parent, testdb, 1, nil)[0] } block := &Block{OriginPeer: id, RawBlock: raw} diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 7db78327b3..431dd59f6f 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -202,7 +202,7 @@ func (q *queue) Insert(headers []*types.Header) []*types.Header { // Queue the header for body retrieval inserts = append(inserts, header) q.headerPool[hash] = header - q.headerQueue.Push(header, -float32(header.Number.Uint64())) + q.headerQueue.Push(header, -float32(header.Number().Uint64())) } return inserts } @@ -340,7 +340,7 @@ func (q *queue) Reserve(p *peer, count int) (*fetchRequest, bool, error) { header := q.headerQueue.PopItem().(*types.Header) // If the header defines an empty block, deliver straight - if header.TxHash == types.DeriveSha(types.Transactions{}) && header.UncleHash == types.CalcUncleHash([]*types.Header{}) { + if header.TxHash() == types.DeriveSha(types.Transactions{}) && header.UncleHash() == types.CalcUncleHash([]*types.Header{}) { if err := q.enqueue("", types.NewBlockWithHeader(header)); err != nil { return nil, false, errInvalidChain } @@ -357,7 +357,7 @@ func (q *queue) Reserve(p *peer, count int) (*fetchRequest, bool, error) { } // Merge all the skipped headers back for _, header := range skip { - q.headerQueue.Push(header, -float32(header.Number.Uint64())) + q.headerQueue.Push(header, -float32(header.Number().Uint64())) } // Assemble and return the block download request if len(send) == 0 { @@ -382,7 +382,7 @@ func (q *queue) Cancel(request *fetchRequest) { q.hashQueue.Push(hash, float32(index)) } for _, header := range request.Headers { - q.headerQueue.Push(header, -float32(header.Number.Uint64())) + q.headerQueue.Push(header, -float32(header.Number().Uint64())) } delete(q.pendPool, request.Peer.id) } @@ -408,7 +408,7 @@ func (q *queue) Expire(timeout time.Duration) []string { q.hashQueue.Push(hash, float32(index)) } for _, header := range request.Headers { - q.headerQueue.Push(header, -float32(header.Number.Uint64())) + q.headerQueue.Push(header, -float32(header.Number().Uint64())) } peers = append(peers, id) } @@ -496,7 +496,7 @@ func (q *queue) Deliver(id string, txLists [][]*types.Transaction, uncleLists [] break } // Reconstruct the next block if contents match up - if types.DeriveSha(types.Transactions(txLists[i])) != header.TxHash || types.CalcUncleHash(uncleLists[i]) != header.UncleHash { + if types.DeriveSha(types.Transactions(txLists[i])) != header.TxHash() || types.CalcUncleHash(uncleLists[i]) != header.UncleHash() { errs = []error{errInvalidBody} break } @@ -513,7 +513,7 @@ func (q *queue) Deliver(id string, txLists [][]*types.Transaction, uncleLists [] // Return all failed or missing fetches to the queue for _, header := range request.Headers { if header != nil { - q.headerQueue.Push(header, -float32(header.Number.Uint64())) + q.headerQueue.Push(header, -float32(header.Number().Uint64())) } } // If none of the blocks were good, it's a stale delivery diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index b8ec1fc554..9d1c8a038e 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -537,8 +537,8 @@ func (f *Fetcher) loop() { // Filter fetcher-requested headers from other synchronisation algorithms if announce := f.fetching[hash]; announce != nil && f.fetched[hash] == nil && f.completing[hash] == nil && f.queued[hash] == nil { // If the delivered header does not match the promised number, drop the announcer - if header.Number.Uint64() != announce.number { - glog.V(logger.Detail).Infof("[eth/62] Peer %s: invalid block number for [%x…]: announced %d, provided %d", announce.origin, header.Hash().Bytes()[:4], announce.number, header.Number.Uint64()) + if header.Number().Uint64() != announce.number { + glog.V(logger.Detail).Infof("[eth/62] Peer %s: invalid block number for [%x…]: announced %d, provided %d", announce.origin, header.Hash().Bytes()[:4], announce.number, header.Number().Uint64()) f.dropPeer(announce.origin) f.forgetHash(hash) continue @@ -549,8 +549,8 @@ func (f *Fetcher) loop() { announce.time = task.time // If the block is empty (header only), short circuit into the final import queue - if header.TxHash == types.DeriveSha(types.Transactions{}) && header.UncleHash == types.CalcUncleHash([]*types.Header{}) { - glog.V(logger.Detail).Infof("[eth/62] Peer %s: block #%d [%x…] empty, skipping body retrieval", announce.origin, header.Number.Uint64(), header.Hash().Bytes()[:4]) + if header.TxHash() == types.DeriveSha(types.Transactions{}) && header.UncleHash() == types.CalcUncleHash([]*types.Header{}) { + glog.V(logger.Detail).Infof("[eth/62] Peer %s: block #%d [%x…] empty, skipping body retrieval", announce.origin, header.Number().Uint64(), header.Hash().Bytes()[:4]) block := types.NewBlockWithHeader(header) block.ReceivedAt = task.time @@ -562,7 +562,7 @@ func (f *Fetcher) loop() { // Otherwise add to the list of blocks needing completion incomplete = append(incomplete, announce) } else { - glog.V(logger.Detail).Infof("[eth/62] Peer %s: block #%d [%x…] already imported, discarding header", announce.origin, header.Number.Uint64(), header.Hash().Bytes()[:4]) + glog.V(logger.Detail).Infof("[eth/62] Peer %s: block #%d [%x…] already imported, discarding header", announce.origin, header.Number().Uint64(), header.Hash().Bytes()[:4]) f.forgetHash(hash) } } else { @@ -614,7 +614,7 @@ func (f *Fetcher) loop() { txnHash := types.DeriveSha(types.Transactions(task.transactions[i])) uncleHash := types.CalcUncleHash(task.uncles[i]) - if txnHash == announce.header.TxHash && uncleHash == announce.header.UncleHash { + if txnHash == announce.header.TxHash() && uncleHash == announce.header.UncleHash() { // Mark the body matched, reassemble if still unknown matched = true diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go index 707d8d7583..fafd171750 100644 --- a/eth/fetcher/fetcher_test.go +++ b/eth/fetcher/fetcher_test.go @@ -37,7 +37,7 @@ var ( testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testAddress = crypto.PubkeyToAddress(testKey.PublicKey) genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000)) - unknownBlock = types.NewBlock(&types.Header{GasLimit: params.GenesisGasLimit}, nil, nil, nil) + unknownBlock = types.NewBlock(&types.RawHeader{GasLimit: params.GenesisGasLimit}, nil, nil, nil) ) // makeChain creates a chain of n blocks starting at and including parent. @@ -58,7 +58,11 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common } // If the block number is a multiple of 5, add a bonus uncle to the block if i%5 == 0 { - block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))}) + uncle := &types.RawHeader{ + ParentHash: block.PrevBlock(i - 1).Hash(), + Number: big.NewInt(int64(i - 1)), + } + block.AddUncle(types.NewHeader(uncle)) } }) hashes := make([]common.Hash, n+1) diff --git a/eth/handler.go b/eth/handler.go index 95f4e8ce21..8e862d9245 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -371,7 +371,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { // Hash based traversal towards the genesis block for i := 0; i < int(query.Skip)+1; i++ { if header := pm.chainman.GetHeader(query.Origin.Hash); header != nil { - query.Origin.Hash = header.ParentHash + query.Origin.Hash = header.ParentHash() } else { unknown = true break @@ -379,7 +379,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { } case query.Origin.Hash != (common.Hash{}) && !query.Reverse: // Hash based traversal towards the leaf block - if header := pm.chainman.GetHeaderByNumber(origin.Number.Uint64() + query.Skip + 1); header != nil { + if header := pm.chainman.GetHeaderByNumber(origin.Number().Uint64() + query.Skip + 1); header != nil { if pm.chainman.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash { query.Origin.Hash = header.Hash() } else { diff --git a/eth/handler_test.go b/eth/handler_test.go index 6400d4e789..64dc239523 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -401,12 +401,12 @@ func testGetNodeData(t *testing.T, protocol int) { block.SetExtra([]byte("yeehaw")) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). - b2 := block.PrevBlock(1).Header() + b2 := block.PrevBlock(1).Header().Raw() b2.Extra = []byte("foo") - block.AddUncle(b2) - b3 := block.PrevBlock(2).Header() + block.AddUncle(types.NewHeader(b2)) + b3 := block.PrevBlock(2).Header().Raw() b3.Extra = []byte("foo") - block.AddUncle(b3) + block.AddUncle(types.NewHeader(b3)) } } // Assemble the test environment @@ -490,12 +490,12 @@ func testGetReceipt(t *testing.T, protocol int) { block.SetExtra([]byte("yeehaw")) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). - b2 := block.PrevBlock(1).Header() + b2 := block.PrevBlock(1).Header().Raw() b2.Extra = []byte("foo") - block.AddUncle(b2) - b3 := block.PrevBlock(2).Header() + block.AddUncle(types.NewHeader(b2)) + b3 := block.PrevBlock(2).Header().Raw() b3.Extra = []byte("foo") - block.AddUncle(b3) + block.AddUncle(types.NewHeader(b3)) } } // Assemble the test environment diff --git a/miner/worker.go b/miner/worker.go index 16a16931d7..c593be698c 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -75,7 +75,7 @@ type Work struct { Block *types.Block // the new block - header *types.Header + header *types.RawHeader txs []*types.Transaction receipts []*types.Receipt @@ -346,7 +346,7 @@ func (self *worker) push(work *Work) { } // makeCurrent creates a new environment for the current cycle. -func (self *worker) makeCurrent(parent *types.Block, header *types.Header) { +func (self *worker) makeCurrent(parent *types.Block, header *types.RawHeader) { state := state.New(parent.Root(), self.eth.ChainDb()) work := &Work{ state: state, @@ -443,9 +443,9 @@ func (self *worker) commitNewWork() { glog.V(logger.Info).Infoln("We are too far in the future. Waiting for", wait) time.Sleep(wait) } - num := parent.Number() - header := &types.Header{ + + header := &types.RawHeader{ ParentHash: parent.Hash(), Number: num.Add(num, common.Big1), Difficulty: core.CalcDifficulty(uint64(tstamp), parent.Time().Uint64(), parent.Number(), parent.Difficulty()), @@ -455,7 +455,6 @@ func (self *worker) commitNewWork() { Extra: self.extra, Time: big.NewInt(tstamp), } - previous := self.current self.makeCurrent(parent, header) work := self.current @@ -526,7 +525,7 @@ func (self *worker) commitNewWork() { if atomic.LoadInt32(&self.mining) == 1 { // commit state root after all state transitions. - core.AccumulateRewards(work.state, header, uncles) + core.AccumulateRewards(work.state, types.NewHeader(header), uncles) work.state.SyncObjects() header.Root = work.state.Root() } @@ -549,8 +548,8 @@ func (self *worker) commitUncle(work *Work, uncle *types.Header) error { if work.uncles.Has(hash) { return core.UncleError("Uncle not unique") } - if !work.ancestors.Has(uncle.ParentHash) { - return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4])) + if parent := uncle.ParentHash(); !work.ancestors.Has(parent) { + return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", parent[:4])) } if work.family.Has(hash) { return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", hash)) @@ -619,7 +618,7 @@ func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *b func (env *Work) commitTransaction(tx *types.Transaction, proc *core.BlockProcessor) error { snap := env.state.Copy() - receipt, _, err := proc.ApplyTransaction(env.coinbase, env.state, env.header, tx, env.header.GasUsed, true) + receipt, _, err := proc.ApplyTransaction(env.coinbase, env.state, types.NewHeader(env.header), tx, env.header.GasUsed, true) if err != nil { env.state.Set(snap) return err diff --git a/rpc/api/parsing.go b/rpc/api/parsing.go index 5858bc1361..f700862bbc 100644 --- a/rpc/api/parsing.go +++ b/rpc/api/parsing.go @@ -383,21 +383,21 @@ func NewUncleRes(h *types.Header) *UncleRes { } var v = new(UncleRes) - v.BlockNumber = newHexNum(h.Number) + v.BlockNumber = newHexNum(h.Number()) v.BlockHash = newHexData(h.Hash()) - v.ParentHash = newHexData(h.ParentHash) - v.Sha3Uncles = newHexData(h.UncleHash) - v.Nonce = newHexData(h.Nonce[:]) - v.LogsBloom = newHexData(h.Bloom) - v.TransactionRoot = newHexData(h.TxHash) - v.StateRoot = newHexData(h.Root) - v.Miner = newHexData(h.Coinbase) - v.Difficulty = newHexNum(h.Difficulty) - v.ExtraData = newHexData(h.Extra) - v.GasLimit = newHexNum(h.GasLimit) - v.GasUsed = newHexNum(h.GasUsed) - v.UnixTimestamp = newHexNum(h.Time) - v.ReceiptHash = newHexData(h.ReceiptHash) + v.ParentHash = newHexData(h.ParentHash()) + v.Sha3Uncles = newHexData(h.UncleHash()) + v.Nonce = newHexData(h.Nonce()) + v.LogsBloom = newHexData(h.Bloom()) + v.TransactionRoot = newHexData(h.TxHash()) + v.StateRoot = newHexData(h.Root()) + v.Miner = newHexData(h.Coinbase()) + v.Difficulty = newHexNum(h.Difficulty()) + v.ExtraData = newHexData(h.Extra()) + v.GasLimit = newHexNum(h.GasLimit()) + v.GasUsed = newHexNum(h.GasUsed()) + v.UnixTimestamp = newHexNum(h.Time()) + v.ReceiptHash = newHexData(h.ReceiptHash()) return v } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 2090afce71..764f550f1b 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -297,77 +297,77 @@ func (t *BlockTest) TryBlocksInsert(chainManager *core.ChainManager) error { func (s *BlockTest) validateBlockHeader(h *btHeader, h2 *types.Header) error { expectedBloom := mustConvertBytes(h.Bloom) - if !bytes.Equal(expectedBloom, h2.Bloom.Bytes()) { - return fmt.Errorf("Bloom: expected: %v, decoded: %v", expectedBloom, h2.Bloom.Bytes()) + if !bytes.Equal(expectedBloom, h2.Bloom().Bytes()) { + return fmt.Errorf("Bloom: expected: %v, decoded: %v", expectedBloom, h2.Bloom().Bytes()) } expectedCoinbase := mustConvertBytes(h.Coinbase) - if !bytes.Equal(expectedCoinbase, h2.Coinbase.Bytes()) { - return fmt.Errorf("Coinbase: expected: %v, decoded: %v", expectedCoinbase, h2.Coinbase.Bytes()) + if !bytes.Equal(expectedCoinbase, h2.Coinbase().Bytes()) { + return fmt.Errorf("Coinbase: expected: %v, decoded: %v", expectedCoinbase, h2.Coinbase().Bytes()) } expectedMixHashBytes := mustConvertBytes(h.MixHash) - if !bytes.Equal(expectedMixHashBytes, h2.MixDigest.Bytes()) { - return fmt.Errorf("MixHash: expected: %v, decoded: %v", expectedMixHashBytes, h2.MixDigest.Bytes()) + if !bytes.Equal(expectedMixHashBytes, h2.MixDigest().Bytes()) { + return fmt.Errorf("MixHash: expected: %v, decoded: %v", expectedMixHashBytes, h2.MixDigest().Bytes()) } expectedNonce := mustConvertBytes(h.Nonce) - if !bytes.Equal(expectedNonce, h2.Nonce[:]) { - return fmt.Errorf("Nonce: expected: %v, decoded: %v", expectedNonce, h2.Nonce) + if nonce := h2.Nonce(); !bytes.Equal(expectedNonce, nonce[:]) { + return fmt.Errorf("Nonce: expected: %v, decoded: %v", expectedNonce, nonce) } expectedNumber := mustConvertBigInt(h.Number, 16) - if expectedNumber.Cmp(h2.Number) != 0 { - return fmt.Errorf("Number: expected: %v, decoded: %v", expectedNumber, h2.Number) + if expectedNumber.Cmp(h2.Number()) != 0 { + return fmt.Errorf("Number: expected: %v, decoded: %v", expectedNumber, h2.Number()) } expectedParentHash := mustConvertBytes(h.ParentHash) - if !bytes.Equal(expectedParentHash, h2.ParentHash.Bytes()) { - return fmt.Errorf("Parent hash: expected: %v, decoded: %v", expectedParentHash, h2.ParentHash.Bytes()) + if !bytes.Equal(expectedParentHash, h2.ParentHash().Bytes()) { + return fmt.Errorf("Parent hash: expected: %v, decoded: %v", expectedParentHash, h2.ParentHash().Bytes()) } expectedReceiptHash := mustConvertBytes(h.ReceiptTrie) - if !bytes.Equal(expectedReceiptHash, h2.ReceiptHash.Bytes()) { - return fmt.Errorf("Receipt hash: expected: %v, decoded: %v", expectedReceiptHash, h2.ReceiptHash.Bytes()) + if !bytes.Equal(expectedReceiptHash, h2.ReceiptHash().Bytes()) { + return fmt.Errorf("Receipt hash: expected: %v, decoded: %v", expectedReceiptHash, h2.ReceiptHash().Bytes()) } expectedTxHash := mustConvertBytes(h.TransactionsTrie) - if !bytes.Equal(expectedTxHash, h2.TxHash.Bytes()) { - return fmt.Errorf("Tx hash: expected: %v, decoded: %v", expectedTxHash, h2.TxHash.Bytes()) + if !bytes.Equal(expectedTxHash, h2.TxHash().Bytes()) { + return fmt.Errorf("Tx hash: expected: %v, decoded: %v", expectedTxHash, h2.TxHash().Bytes()) } expectedStateHash := mustConvertBytes(h.StateRoot) - if !bytes.Equal(expectedStateHash, h2.Root.Bytes()) { - return fmt.Errorf("State hash: expected: %v, decoded: %v", expectedStateHash, h2.Root.Bytes()) + if !bytes.Equal(expectedStateHash, h2.Root().Bytes()) { + return fmt.Errorf("State hash: expected: %v, decoded: %v", expectedStateHash, h2.Root().Bytes()) } expectedUncleHash := mustConvertBytes(h.UncleHash) - if !bytes.Equal(expectedUncleHash, h2.UncleHash.Bytes()) { - return fmt.Errorf("Uncle hash: expected: %v, decoded: %v", expectedUncleHash, h2.UncleHash.Bytes()) + if !bytes.Equal(expectedUncleHash, h2.UncleHash().Bytes()) { + return fmt.Errorf("Uncle hash: expected: %v, decoded: %v", expectedUncleHash, h2.UncleHash().Bytes()) } expectedExtraData := mustConvertBytes(h.ExtraData) - if !bytes.Equal(expectedExtraData, h2.Extra) { - return fmt.Errorf("Extra data: expected: %v, decoded: %v", expectedExtraData, h2.Extra) + if !bytes.Equal(expectedExtraData, h2.Extra()) { + return fmt.Errorf("Extra data: expected: %v, decoded: %v", expectedExtraData, h2.Extra()) } expectedDifficulty := mustConvertBigInt(h.Difficulty, 16) - if expectedDifficulty.Cmp(h2.Difficulty) != 0 { - return fmt.Errorf("Difficulty: expected: %v, decoded: %v", expectedDifficulty, h2.Difficulty) + if expectedDifficulty.Cmp(h2.Difficulty()) != 0 { + return fmt.Errorf("Difficulty: expected: %v, decoded: %v", expectedDifficulty, h2.Difficulty()) } expectedGasLimit := mustConvertBigInt(h.GasLimit, 16) - if expectedGasLimit.Cmp(h2.GasLimit) != 0 { - return fmt.Errorf("GasLimit: expected: %v, decoded: %v", expectedGasLimit, h2.GasLimit) + if expectedGasLimit.Cmp(h2.GasLimit()) != 0 { + return fmt.Errorf("GasLimit: expected: %v, decoded: %v", expectedGasLimit, h2.GasLimit()) } expectedGasUsed := mustConvertBigInt(h.GasUsed, 16) - if expectedGasUsed.Cmp(h2.GasUsed) != 0 { - return fmt.Errorf("GasUsed: expected: %v, decoded: %v", expectedGasUsed, h2.GasUsed) + if expectedGasUsed.Cmp(h2.GasUsed()) != 0 { + return fmt.Errorf("GasUsed: expected: %v, decoded: %v", expectedGasUsed, h2.GasUsed()) } expectedTimestamp := mustConvertBigInt(h.Timestamp, 16) - if expectedTimestamp.Cmp(h2.Time) != 0 { - return fmt.Errorf("Timestamp: expected: %v, decoded: %v", expectedTimestamp, h2.Time) + if expectedTimestamp.Cmp(h2.Time()) != 0 { + return fmt.Errorf("Timestamp: expected: %v, decoded: %v", expectedTimestamp, h2.Time()) } return nil @@ -440,14 +440,14 @@ func convertBlockTest(in *btJSON) (out *BlockTest, err error) { func mustConvertGenesis(testGenesis btHeader) *types.Block { hdr := mustConvertHeader(testGenesis) hdr.Number = big.NewInt(0) - b := types.NewBlockWithHeader(hdr) + b := types.NewBlockWithRawHeader(hdr) b.Td = new(big.Int) return b } -func mustConvertHeader(in btHeader) *types.Header { +func mustConvertHeader(in btHeader) *types.RawHeader { // hex decode these fields - header := &types.Header{ + return &types.RawHeader{ //SeedHash: mustConvertBytes(in.SeedHash), MixDigest: mustConvertHash(in.MixHash), Bloom: mustConvertBloom(in.Bloom), @@ -464,7 +464,6 @@ func mustConvertHeader(in btHeader) *types.Header { Time: mustConvertBigInt(in.Timestamp, 16), Nonce: types.EncodeNonce(mustConvertUint(in.Nonce, 16)), } - return header } func mustConvertBlock(testBlock btBlock) (*types.Block, error) {