diff --git a/api/proto/node/node_test.go b/api/proto/node/node_test.go index b042d1aa4..f7271b92f 100644 --- a/api/proto/node/node_test.go +++ b/api/proto/node/node_test.go @@ -60,14 +60,14 @@ func TestConstructBlocksSyncMessage(t *testing.T) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) root := statedb.IntermediateRoot(false) - head := &block.Header{ - Number: new(big.Int).SetUint64(uint64(10000)), - Epoch: big.NewInt(0), - ShardID: 0, - Time: new(big.Int).SetUint64(uint64(100000)), - Root: root, - } - head.GasLimit = 10000000000 + head := block.NewHeaderWith(). + Number(new(big.Int).SetUint64(uint64(10000))). + Epoch(big.NewInt(0)). + ShardID(0). + Time(new(big.Int).SetUint64(uint64(100000))). + Root(root). + GasLimit(10000000000). + Header() if _, err := statedb.Commit(false); err != nil { t.Fatalf("statedb.Commit() failed: %s", err) diff --git a/api/service/explorer/service.go b/api/service/explorer/service.go index def1e92f5..2ef9999d8 100644 --- a/api/service/explorer/service.go +++ b/api/service/explorer/service.go @@ -235,7 +235,7 @@ func (s *Service) GetExplorerBlocks(w http.ResponseWriter, r *http.Request) { } mask, err := bls2.NewMask(pubkeys, nil) if err == nil && accountBlocks[id+1] != nil { - err = mask.SetMask(accountBlocks[id+1].Header().LastCommitBitmap) + err = mask.SetMask(accountBlocks[id+1].Header().LastCommitBitmap()) if err == nil { for _, validator := range committee.NodeList { oneAddress, err := common2.AddressToBech32(validator.EcdsaAddress) diff --git a/api/service/explorer/storage_test.go b/api/service/explorer/storage_test.go index 91fb22e09..86bf5f29c 100644 --- a/api/service/explorer/storage_test.go +++ b/api/service/explorer/storage_test.go @@ -58,7 +58,7 @@ func TestDump(t *testing.T) { tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), 0, big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}) txs := []*types.Transaction{tx1, tx2, tx3} - block := types.NewBlock(&block2.Header{Number: big.NewInt(314)}, txs, nil, nil, nil) + block := types.NewBlock(block2.NewHeaderWith().Number(big.NewInt(314)).Header(), txs, nil, nil, nil) ins := GetStorageInstance("1.1.1.1", "3333", true) ins.Dump(block, uint64(1)) db := ins.GetDB() @@ -116,7 +116,7 @@ func TestUpdateAddressStorage(t *testing.T) { tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), 0, big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}) txs := []*types.Transaction{tx1, tx2, tx3} - block := types.NewBlock(&block2.Header{Number: big.NewInt(314)}, txs, nil, nil, nil) + block := types.NewBlock(block2.NewHeaderWith().Number(big.NewInt(314)).Header(), txs, nil, nil, nil) ins := GetStorageInstance("1.1.1.1", "3333", true) ins.Dump(block, uint64(1)) db := ins.GetDB() diff --git a/api/service/explorer/structs_test.go b/api/service/explorer/structs_test.go index fcfacd833..c1cca0b49 100644 --- a/api/service/explorer/structs_test.go +++ b/api/service/explorer/structs_test.go @@ -20,7 +20,7 @@ func TestGetTransaction(t *testing.T) { tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), 0, big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}) txs := []*types.Transaction{tx1, tx2, tx3} - block := types.NewBlock(&block2.Header{Number: big.NewInt(314)}, txs, nil, nil, nil) + block := types.NewBlock(block2.NewHeaderWith().Number(big.NewInt(314)).Header(), txs, nil, nil, nil) tx := GetTransaction(tx1, block) assert.Equal(t, tx.ID, tx1.Hash().Hex(), "should be equal tx1.Hash()") diff --git a/api/service/resharding/service.go b/api/service/resharding/service.go index c15660bdd..18558ab39 100644 --- a/api/service/resharding/service.go +++ b/api/service/resharding/service.go @@ -61,11 +61,11 @@ func (s *Service) Run(stopChan chan struct{}, stoppedChan chan struct{}) { func (s *Service) DoService() { tick := time.NewTicker(ReshardingCheckTime) // Get current shard state hash. - currentShardStateHash := s.beaconChain.CurrentBlock().Header().ShardStateHash + currentShardStateHash := s.beaconChain.CurrentBlock().Header().ShardStateHash() for { select { case <-tick.C: - LatestShardStateHash := s.beaconChain.CurrentBlock().Header().ShardStateHash + LatestShardStateHash := s.beaconChain.CurrentBlock().Header().ShardStateHash() if currentShardStateHash != LatestShardStateHash { // TODO(minhdoan): Add resharding logic later after modifying the resharding func as it current doesn't calculate the role (leader/validator) } diff --git a/api/service/syncing/syncing.go b/api/service/syncing/syncing.go index 5c0ed9c00..95294896b 100644 --- a/api/service/syncing/syncing.go +++ b/api/service/syncing/syncing.go @@ -555,7 +555,7 @@ func (ss *StateSync) updateBlockAndStatus(block *types.Block, bc *core.BlockChai return false } ss.syncMux.Lock() - if err := worker.UpdateCurrent(block.Header().Coinbase); err != nil { + if err := worker.UpdateCurrent(block.Header().Coinbase()); err != nil { utils.Logger().Warn().Err(err).Msg("[SYNC] (*Worker).UpdateCurrent failed") } ss.syncMux.Unlock() diff --git a/block/gen_header_json.go b/block/gen_header_json.go index cd05af881..d07baddcb 100644 --- a/block/gen_header_json.go +++ b/block/gen_header_json.go @@ -32,18 +32,18 @@ func (h Header) MarshalJSON() ([]byte, error) { Hash common.Hash `json:"hash"` } var enc Header - enc.ParentHash = h.ParentHash - enc.Coinbase = h.Coinbase - enc.Root = h.Root - enc.TxHash = h.TxHash - enc.ReceiptHash = h.ReceiptHash - enc.Bloom = h.Bloom - enc.Number = (*hexutil.Big)(h.Number) - enc.GasLimit = hexutil.Uint64(h.GasLimit) - enc.GasUsed = hexutil.Uint64(h.GasUsed) - enc.Time = (*hexutil.Big)(h.Time) - enc.Extra = h.Extra - enc.MixDigest = h.MixDigest + enc.ParentHash = h.ParentHash() + enc.Coinbase = h.Coinbase() + enc.Root = h.Root() + enc.TxHash = h.TxHash() + enc.ReceiptHash = h.ReceiptHash() + enc.Bloom = h.Bloom() + enc.Number = (*hexutil.Big)(h.Number()) + enc.GasLimit = hexutil.Uint64(h.GasLimit()) + enc.GasUsed = hexutil.Uint64(h.GasUsed()) + enc.Time = (*hexutil.Big)(h.Time()) + enc.Extra = h.Extra() + enc.MixDigest = h.MixDigest() enc.Hash = h.Hash() return json.Marshal(&enc) } @@ -71,47 +71,47 @@ func (h *Header) UnmarshalJSON(input []byte) error { if dec.ParentHash == nil { return errors.New("missing required field 'parentHash' for Header") } - h.ParentHash = *dec.ParentHash + h.SetParentHash(*dec.ParentHash) if dec.Coinbase == nil { return errors.New("missing required field 'miner' for Header") } - h.Coinbase = *dec.Coinbase + h.SetCoinbase(*dec.Coinbase) if dec.Root == nil { return errors.New("missing required field 'stateRoot' for Header") } - h.Root = *dec.Root + h.SetRoot(*dec.Root) if dec.TxHash == nil { return errors.New("missing required field 'transactionsRoot' for Header") } - h.TxHash = *dec.TxHash + h.SetTxHash(*dec.TxHash) if dec.ReceiptHash == nil { return errors.New("missing required field 'receiptsRoot' for Header") } - h.ReceiptHash = *dec.ReceiptHash + h.SetReceiptHash(*dec.ReceiptHash) if dec.Bloom == nil { return errors.New("missing required field 'logsBloom' for Header") } - h.Bloom = *dec.Bloom - h.Number = (*big.Int)(dec.Number) + h.SetBloom(*dec.Bloom) + h.SetNumber((*big.Int)(dec.Number)) if dec.GasLimit == nil { return errors.New("missing required field 'gasLimit' for Header") } - h.GasLimit = uint64(*dec.GasLimit) + h.SetGasLimit(uint64(*dec.GasLimit)) if dec.GasUsed == nil { return errors.New("missing required field 'gasUsed' for Header") } - h.GasUsed = uint64(*dec.GasUsed) + h.SetGasUsed(uint64(*dec.GasUsed)) if dec.Time == nil { return errors.New("missing required field 'timestamp' for Header") } - h.Time = (*big.Int)(dec.Time) + h.SetTime((*big.Int)(dec.Time)) if dec.Extra == nil { return errors.New("missing required field 'extraData' for Header") } - h.Extra = *dec.Extra + h.SetExtra(*dec.Extra) if dec.MixDigest == nil { return errors.New("missing required field 'mixHash' for Header") } - h.MixDigest = *dec.MixDigest + h.SetMixDigest(*dec.MixDigest) return nil } diff --git a/block/header.go b/block/header.go index 6ae3f25ca..8c5274d47 100644 --- a/block/header.go +++ b/block/header.go @@ -1,6 +1,7 @@ package block import ( + "io" "math/big" "unsafe" @@ -16,6 +17,30 @@ import ( // Header represents a block header in the Harmony blockchain. type Header struct { + fields headerFields +} + +// EncodeRLP encodes the header fields into RLP format. +func (h *Header) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, &h.fields) +} + +// DecodeRLP decodes the given RLP decode stream into the header fields. +func (h *Header) DecodeRLP(s *rlp.Stream) error { + return s.Decode(&h.fields) +} + +// NewHeader creates a new header object. +func NewHeader() *Header { + return &Header{headerFields{ + Number: new(big.Int), + Time: new(big.Int), + ViewID: new(big.Int), + Epoch: new(big.Int), + }} +} + +type headerFields struct { ParentHash common.Hash `json:"parentHash" gencodec:"required"` Coinbase common.Address `json:"miner" gencodec:"required"` Root common.Hash `json:"stateRoot" gencodec:"required"` @@ -43,6 +68,301 @@ type Header struct { CrossLinks []byte `json:"crossLink"` } +// ParentHash is the header hash of the parent block. For the genesis block +// which has no parent by definition, this field is zeroed out. +func (h *Header) ParentHash() common.Hash { + return h.fields.ParentHash +} + +// SetParentHash sets the parent hash field. +func (h *Header) SetParentHash(newParentHash common.Hash) { + h.fields.ParentHash = newParentHash +} + +// Coinbase is the address of the node that proposed this block and all +// transactions in it. +func (h *Header) Coinbase() common.Address { + return h.fields.Coinbase +} + +// SetCoinbase sets the coinbase address field. +func (h *Header) SetCoinbase(newCoinbase common.Address) { + h.fields.Coinbase = newCoinbase +} + +// Root is the state (account) trie root hash. +func (h *Header) Root() common.Hash { + return h.fields.Root +} + +// SetRoot sets the state trie root hash field. +func (h *Header) SetRoot(newRoot common.Hash) { + h.fields.Root = newRoot +} + +// TxHash is the transaction trie root hash. +func (h *Header) TxHash() common.Hash { + return h.fields.TxHash +} + +// SetTxHash sets the transaction trie root hash field. +func (h *Header) SetTxHash(newTxHash common.Hash) { + h.fields.TxHash = newTxHash +} + +// ReceiptHash is the same-shard transaction receipt trie hash. +func (h *Header) ReceiptHash() common.Hash { + return h.fields.ReceiptHash +} + +// SetReceiptHash sets the same-shard transaction receipt trie hash. +func (h *Header) SetReceiptHash(newReceiptHash common.Hash) { + h.fields.ReceiptHash = newReceiptHash +} + +// OutgoingReceiptHash is the egress transaction receipt trie hash. +func (h *Header) OutgoingReceiptHash() common.Hash { + return h.fields.OutgoingReceiptHash +} + +// SetOutgoingReceiptHash sets the egress transaction receipt trie hash. +func (h *Header) SetOutgoingReceiptHash(newOutgoingReceiptHash common.Hash) { + h.fields.OutgoingReceiptHash = newOutgoingReceiptHash +} + +// IncomingReceiptHash is the ingress transaction receipt trie hash. +func (h *Header) IncomingReceiptHash() common.Hash { + return h.fields.IncomingReceiptHash +} + +// SetIncomingReceiptHash sets the ingress transaction receipt trie hash. +func (h *Header) SetIncomingReceiptHash(newIncomingReceiptHash common.Hash) { + h.fields.IncomingReceiptHash = newIncomingReceiptHash +} + +// Bloom is the Bloom filter that indexes accounts and topics logged by smart +// contract transactions (executions) in this block. +func (h *Header) Bloom() types.Bloom { + return h.fields.Bloom +} + +// SetBloom sets the smart contract log Bloom filter for this block. +func (h *Header) SetBloom(newBloom types.Bloom) { + h.fields.Bloom = newBloom +} + +// Number is the block number. +// +// The returned instance is a copy; the caller may do anything with it. +func (h *Header) Number() *big.Int { + return new(big.Int).Set(h.fields.Number) +} + +// SetNumber sets the block number. +// +// It stores a copy; the caller may freely modify the original. +func (h *Header) SetNumber(newNumber *big.Int) { + h.fields.Number = new(big.Int).Set(newNumber) +} + +// GasLimit is the gas limit for transactions in this block. +func (h *Header) GasLimit() uint64 { + return h.fields.GasLimit +} + +// SetGasLimit sets the gas limit for transactions in this block. +func (h *Header) SetGasLimit(newGasLimit uint64) { + h.fields.GasLimit = newGasLimit +} + +// GasUsed is the amount of gas used by transactions in this block. +func (h *Header) GasUsed() uint64 { + return h.fields.GasUsed +} + +// SetGasUsed sets the amount of gas used by transactions in this block. +func (h *Header) SetGasUsed(newGasUsed uint64) { + h.fields.GasUsed = newGasUsed +} + +// Time is the UNIX timestamp of this block. +// +// The returned instance is a copy; the caller may do anything with it. +func (h *Header) Time() *big.Int { + return new(big.Int).Set(h.fields.Time) +} + +// SetTime sets the UNIX timestamp of this block. +// +// It stores a copy; the caller may freely modify the original. +func (h *Header) SetTime(newTime *big.Int) { + h.fields.Time = new(big.Int).Set(newTime) +} + +// Extra is the extra data field of this block. +// +// The returned slice is a copy; the caller may do anything with it. +func (h *Header) Extra() []byte { + return append(h.fields.Extra[:0:0], h.fields.Extra...) +} + +// SetExtra sets the extra data field of this block. +// +// It stores a copy; the caller may freely modify the original. +func (h *Header) SetExtra(newExtra []byte) { + h.fields.Extra = append(newExtra[:0:0], newExtra...) +} + +// MixDigest is the mixhash. +// +// This field is a remnant from Ethereum, and Harmony does not use it and always +// zeroes it out. +func (h *Header) MixDigest() common.Hash { + return h.fields.MixDigest +} + +// SetMixDigest sets the mixhash of this block. +func (h *Header) SetMixDigest(newMixDigest common.Hash) { + h.fields.MixDigest = newMixDigest +} + +// ViewID is the ID of the view in which this block was originally proposed. +// +// It normally increases by one for each subsequent block, or by more than one +// if one or more PBFT/FBFT view changes have occurred. +// +// The returned instance is a copy; the caller may do anything with it. +func (h *Header) ViewID() *big.Int { + return new(big.Int).Set(h.fields.ViewID) +} + +// SetViewID sets the view ID in which the block was originally proposed. +// +// It stores a copy; the caller may freely modify the original. +func (h *Header) SetViewID(newViewID *big.Int) { + h.fields.ViewID = new(big.Int).Set(newViewID) +} + +// Epoch is the epoch number of this block. +// +// The returned instance is a copy; the caller may do anything with it. +func (h *Header) Epoch() *big.Int { + return new(big.Int).Set(h.fields.Epoch) +} + +// SetEpoch sets the epoch number of this block. +// +// It stores a copy; the caller may freely modify the original. +func (h *Header) SetEpoch(newEpoch *big.Int) { + h.fields.Epoch = new(big.Int).Set(newEpoch) +} + +// ShardID is the shard ID to which this block belongs. +func (h *Header) ShardID() uint32 { + return h.fields.ShardID +} + +// SetShardID sets the shard ID to which this block belongs. +func (h *Header) SetShardID(newShardID uint32) { + h.fields.ShardID = newShardID +} + +// LastCommitSignature is the FBFT commit group signature for the last block. +func (h *Header) LastCommitSignature() [96]byte { + return h.fields.LastCommitSignature +} + +// SetLastCommitSignature sets the FBFT commit group signature for the last +// block. +func (h *Header) SetLastCommitSignature(newLastCommitSignature [96]byte) { + h.fields.LastCommitSignature = newLastCommitSignature +} + +// LastCommitBitmap is the signatory bitmap of the previous block. Bit +// positions index into committee member array. +// +// The returned slice is a copy; the caller may do anything with it. +func (h *Header) LastCommitBitmap() []byte { + return append(h.fields.LastCommitBitmap[:0:0], h.fields.LastCommitBitmap...) +} + +// SetLastCommitBitmap sets the signatory bitmap of the previous block. +// +// It stores a copy; the caller may freely modify the original. +func (h *Header) SetLastCommitBitmap(newLastCommitBitmap []byte) { + h.fields.LastCommitBitmap = append(newLastCommitBitmap[:0:0], newLastCommitBitmap...) +} + +// ShardStateHash is the shard state hash. +func (h *Header) ShardStateHash() common.Hash { + return h.fields.ShardStateHash +} + +// SetShardStateHash sets the shard state hash. +func (h *Header) SetShardStateHash(newShardStateHash common.Hash) { + h.fields.ShardStateHash = newShardStateHash +} + +// Vrf is the output of the VRF for the epoch. +// +// The returned slice is a copy; the caller may do anything with it. +func (h *Header) Vrf() []byte { + return append(h.fields.Vrf[:0:0], h.fields.Vrf...) +} + +// SetVrf sets the output of the VRF for the epoch. +// +// It stores a copy; the caller may freely modify the original. +func (h *Header) SetVrf(newVrf []byte) { + h.fields.Vrf = append(newVrf[:0:0], newVrf...) +} + +// Vdf is the output of the VDF for the epoch. +// +// The returned slice is a copy; the caller may do anything with it. +func (h *Header) Vdf() []byte { + return append(h.fields.Vdf[:0:0], h.fields.Vdf...) +} + +// SetVdf sets the output of the VDF for the epoch. +// +// It stores a copy; the caller may freely modify the original. +func (h *Header) SetVdf(newVdf []byte) { + h.fields.Vdf = append(newVdf[:0:0], newVdf...) +} + +// ShardState is the RLP-encoded form of shard state (list of committees) for +// the next epoch. +// +// The returned slice is a copy; the caller may do anything with it. +func (h *Header) ShardState() []byte { + return append(h.fields.ShardState[:0:0], h.fields.ShardState...) +} + +// SetShardState sets the RLP-encoded form of shard state +// +// It stores a copy; the caller may freely modify the original. +func (h *Header) SetShardState(newShardState []byte) { + h.fields.ShardState = append(newShardState[:0:0], newShardState...) +} + +// CrossLinks is the RLP-encoded form of non-beacon block headers chosen to be +// canonical by the beacon committee. This field is present only on beacon +// chain block headers. +// +// The returned slice is a copy; the caller may do anything with it. +func (h *Header) CrossLinks() []byte { + return append(h.fields.CrossLinks[:0:0], h.fields.CrossLinks...) +} + +// SetCrossLinks sets the RLP-encoded form of non-beacon block headers chosen to +// be canonical by the beacon committee. +// +// It stores a copy; the caller may freely modify the original. +func (h *Header) SetCrossLinks(newCrossLinks []byte) { + h.fields.CrossLinks = append(newCrossLinks[:0:0], newCrossLinks...) +} + // field type overrides for gencodec type headerMarshaling struct { Difficulty *hexutil.Big @@ -64,7 +384,7 @@ func (h *Header) Hash() common.Hash { // to approximate and limit the memory consumption of various caches. func (h *Header) Size() common.StorageSize { // TODO: update with new fields - return common.StorageSize(unsafe.Sizeof(*h)) + common.StorageSize(len(h.Extra)+(h.Number.BitLen()+h.Time.BitLen())/8) + return common.StorageSize(unsafe.Sizeof(*h)) + common.StorageSize(len(h.Extra())+(h.Number().BitLen()+h.Time().BitLen())/8) } // Logger returns a sub-logger with block contexts added. @@ -72,9 +392,9 @@ func (h *Header) Logger(logger *zerolog.Logger) *zerolog.Logger { nlogger := logger. With(). Str("blockHash", h.Hash().Hex()). - Uint32("blockShard", h.ShardID). - Uint64("blockEpoch", h.Epoch.Uint64()). - Uint64("blockNumber", h.Number.Uint64()). + Uint32("blockShard", h.ShardID()). + Uint64("blockEpoch", h.Epoch().Uint64()). + Uint64("blockNumber", h.Number().Uint64()). Logger() return &nlogger } @@ -82,9 +402,202 @@ func (h *Header) Logger(logger *zerolog.Logger) *zerolog.Logger { // GetShardState returns the deserialized shard state object. func (h *Header) GetShardState() (shard.State, error) { shardState := shard.State{} - err := rlp.DecodeBytes(h.ShardState, &shardState) + err := rlp.DecodeBytes(h.ShardState(), &shardState) if err != nil { return nil, err } return shardState, nil } + +// HeaderFieldSetter is a header field setter. +// +// See NewHeaderWith for how it is used. +type HeaderFieldSetter struct { + h *Header +} + +// NewHeaderWith creates a new header and returns its field setter context. +// +// Call a chain of setters on the returned field setter, followed by a call of +// Header method. Example: +// +// header := NewHeaderWith(). +// ParentHash(parent.Hash()). +// Epoch(parent.Epoch()). +// ShardID(parent.ShardID()). +// Number(new(big.Int).Add(parent.Number(), big.NewInt(1)). +// Header() +func NewHeaderWith() *HeaderFieldSetter { + return (*HeaderFieldSetter)(&HeaderFieldSetter{h: NewHeader()}) +} + +// ParentHash sets the parent hash field. +func (s HeaderFieldSetter) ParentHash(newParentHash common.Hash) HeaderFieldSetter { + s.h.SetParentHash(newParentHash) + return s +} + +// Coinbase sets the coinbase address field. +func (s HeaderFieldSetter) Coinbase(newCoinbase common.Address) HeaderFieldSetter { + s.h.SetCoinbase(newCoinbase) + return s +} + +// Root sets the state trie root hash field. +func (s HeaderFieldSetter) Root(newRoot common.Hash) HeaderFieldSetter { + s.h.SetRoot(newRoot) + return s +} + +// TxHash sets the transaction trie root hash field. +func (s HeaderFieldSetter) TxHash(newTxHash common.Hash) HeaderFieldSetter { + s.h.SetTxHash(newTxHash) + return s +} + +// ReceiptHash sets the same-shard transaction receipt trie hash. +func (s HeaderFieldSetter) ReceiptHash(newReceiptHash common.Hash) HeaderFieldSetter { + s.h.SetReceiptHash(newReceiptHash) + return s +} + +// OutgoingReceiptHash sets the egress transaction receipt trie hash. +func (s HeaderFieldSetter) OutgoingReceiptHash(newOutgoingReceiptHash common.Hash) HeaderFieldSetter { + s.h.SetOutgoingReceiptHash(newOutgoingReceiptHash) + return s +} + +// IncomingReceiptHash sets the ingress transaction receipt trie hash. +func (s HeaderFieldSetter) IncomingReceiptHash(newIncomingReceiptHash common.Hash) HeaderFieldSetter { + s.h.SetIncomingReceiptHash(newIncomingReceiptHash) + return s +} + +// Bloom sets the smart contract log Bloom filter for this block. +func (s HeaderFieldSetter) Bloom(newBloom types.Bloom) HeaderFieldSetter { + s.h.SetBloom(newBloom) + return s +} + +// Number sets the block number. +// +// It stores a copy; the caller may freely modify the original. +func (s HeaderFieldSetter) Number(newNumber *big.Int) HeaderFieldSetter { + s.h.SetNumber(newNumber) + return s +} + +// GasLimit sets the gas limit for transactions in this block. +func (s HeaderFieldSetter) GasLimit(newGasLimit uint64) HeaderFieldSetter { + s.h.SetGasLimit(newGasLimit) + return s +} + +// GasUsed sets the amount of gas used by transactions in this block. +func (s HeaderFieldSetter) GasUsed(newGasUsed uint64) HeaderFieldSetter { + s.h.SetGasUsed(newGasUsed) + return s +} + +// Time sets the UNIX timestamp of this block. +// +// It stores a copy; the caller may freely modify the original. +func (s HeaderFieldSetter) Time(newTime *big.Int) HeaderFieldSetter { + s.h.SetTime(newTime) + return s +} + +// Extra sets the extra data field of this block. +// +// It stores a copy; the caller may freely modify the original. +func (s HeaderFieldSetter) Extra(newExtra []byte) HeaderFieldSetter { + s.h.SetExtra(newExtra) + return s +} + +// MixDigest sets the mixhash of this block. +func (s HeaderFieldSetter) MixDigest(newMixDigest common.Hash) HeaderFieldSetter { + s.h.SetMixDigest(newMixDigest) + return s +} + +// ViewID sets the view ID in which the block was originally proposed. +// +// It stores a copy; the caller may freely modify the original. +func (s HeaderFieldSetter) ViewID(newViewID *big.Int) HeaderFieldSetter { + s.h.SetViewID(newViewID) + return s +} + +// Epoch sets the epoch number of this block. +// +// It stores a copy; the caller may freely modify the original. +func (s HeaderFieldSetter) Epoch(newEpoch *big.Int) HeaderFieldSetter { + s.h.SetEpoch(newEpoch) + return s +} + +// ShardID sets the shard ID to which this block belongs. +func (s HeaderFieldSetter) ShardID(newShardID uint32) HeaderFieldSetter { + s.h.SetShardID(newShardID) + return s +} + +// LastCommitSignature sets the FBFT commit group signature for the last block. +func (s HeaderFieldSetter) LastCommitSignature(newLastCommitSignature [96]byte) HeaderFieldSetter { + s.h.SetLastCommitSignature(newLastCommitSignature) + return s +} + +// LastCommitBitmap sets the signatory bitmap of the previous block. +// +// It stores a copy; the caller may freely modify the original. +func (s HeaderFieldSetter) LastCommitBitmap(newLastCommitBitmap []byte) HeaderFieldSetter { + s.h.SetLastCommitBitmap(newLastCommitBitmap) + return s +} + +// ShardStateHash sets the shard state hash. +func (s HeaderFieldSetter) ShardStateHash(newShardStateHash common.Hash) HeaderFieldSetter { + s.h.SetShardStateHash(newShardStateHash) + return s +} + +// Vrf sets the output of the VRF for the epoch. +// +// It stores a copy; the caller may freely modify the original. +func (s HeaderFieldSetter) Vrf(newVrf []byte) HeaderFieldSetter { + s.h.SetVrf(newVrf) + return s +} + +// Vdf sets the output of the VDF for the epoch. +// +// It stores a copy; the caller may freely modify the original. +func (s HeaderFieldSetter) Vdf(newVdf []byte) HeaderFieldSetter { + s.h.SetVdf(newVdf) + return s +} + +// ShardState sets the RLP-encoded form of shard state +// +// It stores a copy; the caller may freely modify the original. +func (s HeaderFieldSetter) ShardState(newShardState []byte) HeaderFieldSetter { + s.h.SetShardState(newShardState) + return s +} + +// CrossLinks sets the RLP-encoded form of non-beacon block headers chosen to be +// canonical by the beacon committee. +// +// It stores a copy; the caller may freely modify the original. +func (s HeaderFieldSetter) CrossLinks(newCrossLinks []byte) HeaderFieldSetter { + s.h.SetCrossLinks(newCrossLinks) + return s +} + +// Header returns the header whose fields have been set. Call this at the end +// of a field setter chain. +func (s HeaderFieldSetter) Header() *Header { + return s.h +} diff --git a/consensus/consensus_service.go b/consensus/consensus_service.go index d255f6f9c..70db72575 100644 --- a/consensus/consensus_service.go +++ b/consensus/consensus_service.go @@ -458,35 +458,35 @@ func (consensus *Consensus) getLogger() *zerolog.Logger { // retrieve corresponding blsPublicKey from Coinbase Address func (consensus *Consensus) getLeaderPubKeyFromCoinbase(header *block.Header) (*bls.PublicKey, error) { - shardState, err := consensus.ChainReader.ReadShardState(header.Epoch) + shardState, err := consensus.ChainReader.ReadShardState(header.Epoch()) if err != nil { return nil, ctxerror.New("cannot read shard state", - "epoch", header.Epoch, - "coinbaseAddr", header.Coinbase, + "epoch", header.Epoch(), + "coinbaseAddr", header.Coinbase(), ).WithCause(err) } - committee := shardState.FindCommitteeByID(header.ShardID) + committee := shardState.FindCommitteeByID(header.ShardID()) if committee == nil { return nil, ctxerror.New("cannot find shard in the shard state", - "blockNum", header.Number, - "shardID", header.ShardID, - "coinbaseAddr", header.Coinbase, + "blockNum", header.Number(), + "shardID", header.ShardID(), + "coinbaseAddr", header.Coinbase(), ) } committerKey := new(bls.PublicKey) for _, member := range committee.NodeList { - if member.EcdsaAddress == header.Coinbase { + if member.EcdsaAddress == header.Coinbase() { err := member.BlsPublicKey.ToLibBLSPublicKey(committerKey) if err != nil { return nil, ctxerror.New("cannot convert BLS public key", "blsPublicKey", member.BlsPublicKey, - "coinbaseAddr", header.Coinbase).WithCause(err) + "coinbaseAddr", header.Coinbase()).WithCause(err) } return committerKey, nil } } - return nil, ctxerror.New("cannot find corresponding BLS Public Key", "coinbaseAddr", header.Coinbase) + return nil, ctxerror.New("cannot find corresponding BLS Public Key", "coinbaseAddr", header.Coinbase()) } // UpdateConsensusInformation will update shard information (epoch, publicKeys, blockNum, viewID) @@ -505,8 +505,8 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode { header := consensus.ChainReader.CurrentHeader() - epoch := header.Epoch - curPubKeys := core.GetPublicKeys(epoch, header.ShardID) + epoch := header.Epoch() + curPubKeys := core.GetPublicKeys(epoch, header.ShardID()) consensus.numPrevPubKeys = len(curPubKeys) consensus.getLogger().Info().Msg("[UpdateConsensusInformation] Updating.....") @@ -514,9 +514,9 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode { if core.IsEpochLastBlockByHeader(header) { // increase epoch by one if it's the last block consensus.SetEpochNum(epoch.Uint64() + 1) - consensus.getLogger().Info().Uint64("headerNum", header.Number.Uint64()).Msg("[UpdateConsensusInformation] Epoch updated for next epoch") + consensus.getLogger().Info().Uint64("headerNum", header.Number().Uint64()).Msg("[UpdateConsensusInformation] Epoch updated for next epoch") nextEpoch := new(big.Int).Add(epoch, common.Big1) - pubKeys = core.GetPublicKeys(nextEpoch, header.ShardID) + pubKeys = core.GetPublicKeys(nextEpoch, header.ShardID()) } else { consensus.SetEpochNum(epoch.Uint64()) pubKeys = curPubKeys @@ -534,7 +534,7 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode { consensus.UpdatePublicKeys(pubKeys) // take care of possible leader change during the epoch - if !core.IsEpochLastBlockByHeader(header) && header.Number.Uint64() != 0 { + if !core.IsEpochLastBlockByHeader(header) && header.Number().Uint64() != 0 { leaderPubKey, err := consensus.getLeaderPubKeyFromCoinbase(header) if err != nil || leaderPubKey == nil { consensus.getLogger().Debug().Err(err).Msg("[SYNC] Unable to get leaderPubKey from coinbase") diff --git a/consensus/consensus_v2.go b/consensus/consensus_v2.go index 0e196a0ac..43cb01c51 100644 --- a/consensus/consensus_v2.go +++ b/consensus/consensus_v2.go @@ -184,8 +184,8 @@ func (consensus *Consensus) onAnnounce(msg *msg_pb.Message) { // verify validity of block header object blockHeader := recvMsg.Payload - var headerObj block.Header - err = rlp.DecodeBytes(blockHeader, &headerObj) + headerObj := block.NewHeader() + err = rlp.DecodeBytes(blockHeader, headerObj) if err != nil { consensus.getLogger().Warn(). Err(err). @@ -194,35 +194,35 @@ func (consensus *Consensus) onAnnounce(msg *msg_pb.Message) { return } - if recvMsg.BlockNum < consensus.blockNum || recvMsg.BlockNum != headerObj.Number.Uint64() { + if recvMsg.BlockNum < consensus.blockNum || recvMsg.BlockNum != headerObj.Number().Uint64() { consensus.getLogger().Debug(). Uint64("MsgBlockNum", recvMsg.BlockNum). Uint64("blockNum", consensus.blockNum). - Uint64("hdrBlockNum", headerObj.Number.Uint64()). + Uint64("hdrBlockNum", headerObj.Number().Uint64()). Msg("[OnAnnounce] BlockNum does not match") return } if consensus.mode.Mode() == Normal { - if err = chain.Engine.VerifyHeader(consensus.ChainReader, &headerObj, true); err != nil { + if err = chain.Engine.VerifyHeader(consensus.ChainReader, headerObj, true); err != nil { consensus.getLogger().Warn(). Err(err). - Str("inChain", consensus.ChainReader.CurrentHeader().Number.String()). - Str("MsgBlockNum", headerObj.Number.String()). + Str("inChain", consensus.ChainReader.CurrentHeader().Number().String()). + Str("MsgBlockNum", headerObj.Number().String()). Msg("[OnAnnounce] Block content is not verified successfully") return } //VRF/VDF is only generated in the beach chain - if consensus.NeedsRandomNumberGeneration(headerObj.Epoch) { + if consensus.NeedsRandomNumberGeneration(headerObj.Epoch()) { //validate the VRF with proof if a non zero VRF is found in header - if len(headerObj.Vrf) > 0 { + if len(headerObj.Vrf()) > 0 { if !consensus.ValidateVrfAndProof(headerObj) { return } } //validate the VDF with proof if a non zero VDF is found in header - if len(headerObj.Vdf) > 0 { + if len(headerObj.Vdf()) > 0 { if !consensus.ValidateVdfAndProof(headerObj) { return } @@ -513,8 +513,8 @@ func (consensus *Consensus) onPrepared(msg *msg_pb.Message) { if err := chain.Engine.VerifyHeader(consensus.ChainReader, blockObj.Header(), true); err != nil { consensus.getLogger().Warn(). Err(err). - Str("inChain", consensus.ChainReader.CurrentHeader().Number.String()). - Str("MsgBlockNum", blockObj.Header().Number.String()). + Str("inChain", consensus.ChainReader.CurrentHeader().Number().String()). + Str("MsgBlockNum", blockObj.Header().Number().String()). Msg("[OnPrepared] Block header is not verified successfully") return } @@ -1062,14 +1062,14 @@ func (consensus *Consensus) Start(blockChannel chan *types.Block, stopChan chan } } case <-consensus.syncReadyChan: - consensus.SetBlockNum(consensus.ChainReader.CurrentHeader().Number.Uint64() + 1) - consensus.SetViewID(consensus.ChainReader.CurrentHeader().ViewID.Uint64() + 1) + consensus.SetBlockNum(consensus.ChainReader.CurrentHeader().Number().Uint64() + 1) + consensus.SetViewID(consensus.ChainReader.CurrentHeader().ViewID().Uint64() + 1) mode := consensus.UpdateConsensusInformation() consensus.mode.SetMode(mode) consensus.getLogger().Info().Str("Mode", mode.String()).Msg("Node is in sync") case <-consensus.syncNotReadyChan: - consensus.SetBlockNum(consensus.ChainReader.CurrentHeader().Number.Uint64() + 1) + consensus.SetBlockNum(consensus.ChainReader.CurrentHeader().Number().Uint64() + 1) consensus.mode.SetMode(Syncing) consensus.getLogger().Info().Msg("Node is out of sync") @@ -1079,14 +1079,14 @@ func (consensus *Consensus) Start(blockChannel chan *types.Block, stopChan chan Msg("[ConsensusMainLoop] Received Proposed New Block!") //VRF/VDF is only generated in the beacon chain - if consensus.NeedsRandomNumberGeneration(newBlock.Header().Epoch) { + if consensus.NeedsRandomNumberGeneration(newBlock.Header().Epoch()) { // generate VRF if the current block has a new leader if !consensus.ChainReader.IsSameLeaderAsPreviousBlock(newBlock) { - vrfBlockNumbers, err := consensus.ChainReader.ReadEpochVrfBlockNums(newBlock.Header().Epoch) + vrfBlockNumbers, err := consensus.ChainReader.ReadEpochVrfBlockNums(newBlock.Header().Epoch()) if err != nil { consensus.getLogger().Info(). Uint64("MsgBlockNum", newBlock.NumberU64()). - Uint64("Epoch", newBlock.Header().Epoch.Uint64()). + Uint64("Epoch", newBlock.Header().Epoch().Uint64()). Msg("[ConsensusMainLoop] no VRF block number from local db") } @@ -1096,7 +1096,7 @@ func (consensus *Consensus) Start(blockChannel chan *types.Block, stopChan chan if v == newBlock.NumberU64() { consensus.getLogger().Info(). Uint64("MsgBlockNum", newBlock.NumberU64()). - Uint64("Epoch", newBlock.Header().Epoch.Uint64()). + Uint64("Epoch", newBlock.Header().Epoch().Uint64()). Msg("[ConsensusMainLoop] VRF is already generated for this block") vrfAlreadyGenerated = true break @@ -1113,7 +1113,7 @@ func (consensus *Consensus) Start(blockChannel chan *types.Block, stopChan chan if (!vdfInProgress) && len(vrfBlockNumbers) >= consensus.VdfSeedSize() { //check local database to see if there's a VDF generated for this epoch //generate a VDF if no blocknum is available - _, err := consensus.ChainReader.ReadEpochVdfBlockNum(newBlock.Header().Epoch) + _, err := consensus.ChainReader.ReadEpochVdfBlockNum(newBlock.Header().Epoch()) if err != nil { consensus.GenerateVdfAndProof(newBlock, vrfBlockNumbers) vdfInProgress = true @@ -1130,20 +1130,20 @@ func (consensus *Consensus) Start(blockChannel chan *types.Block, stopChan chan if !vdfObject.Verify(vdfOutput) { consensus.getLogger().Warn(). Uint64("MsgBlockNum", newBlock.NumberU64()). - Uint64("Epoch", newBlock.Header().Epoch.Uint64()). + Uint64("Epoch", newBlock.Header().Epoch().Uint64()). Msg("[ConsensusMainLoop] failed to verify the VDF output") } else { //write the VDF only if VDF has not been generated - _, err := consensus.ChainReader.ReadEpochVdfBlockNum(newBlock.Header().Epoch) + _, err := consensus.ChainReader.ReadEpochVdfBlockNum(newBlock.Header().Epoch()) if err == nil { consensus.getLogger().Info(). Uint64("MsgBlockNum", newBlock.NumberU64()). - Uint64("Epoch", newBlock.Header().Epoch.Uint64()). + Uint64("Epoch", newBlock.Header().Epoch().Uint64()). Msg("[ConsensusMainLoop] VDF has already been generated previously") } else { consensus.getLogger().Info(). Uint64("MsgBlockNum", newBlock.NumberU64()). - Uint64("Epoch", newBlock.Header().Epoch.Uint64()). + Uint64("Epoch", newBlock.Header().Epoch().Uint64()). Msg("[ConsensusMainLoop] Generated a new VDF") newBlock.AddVdf(vdfOutput[:]) @@ -1197,7 +1197,7 @@ func (consensus *Consensus) GenerateVrfAndProof(newBlock *types.Block, vrfBlockN consensus.getLogger().Info(). Uint64("MsgBlockNum", newBlock.NumberU64()). - Uint64("Epoch", newBlock.Header().Epoch.Uint64()). + Uint64("Epoch", newBlock.Header().Epoch().Uint64()). Int("Num of VRF", len(vrfBlockNumbers)). Msg("[ConsensusMainLoop] Leader generated a VRF") @@ -1205,35 +1205,35 @@ func (consensus *Consensus) GenerateVrfAndProof(newBlock *types.Block, vrfBlockN } // ValidateVrfAndProof validates a VRF/Proof from hash of previous block -func (consensus *Consensus) ValidateVrfAndProof(headerObj block.Header) bool { +func (consensus *Consensus) ValidateVrfAndProof(headerObj *block.Header) bool { vrfPk := vrf_bls.NewVRFVerifier(consensus.LeaderPubKey) var blockHash [32]byte - previousHeader := consensus.ChainReader.GetHeaderByNumber(headerObj.Number.Uint64() - 1) + previousHeader := consensus.ChainReader.GetHeaderByNumber(headerObj.Number().Uint64() - 1) previousHash := previousHeader.Hash() copy(blockHash[:], previousHash[:]) vrfProof := [96]byte{} - copy(vrfProof[:], headerObj.Vrf[32:]) + copy(vrfProof[:], headerObj.Vrf()[32:]) hash, err := vrfPk.ProofToHash(blockHash[:], vrfProof[:]) if err != nil { consensus.getLogger().Warn(). Err(err). - Str("MsgBlockNum", headerObj.Number.String()). + Str("MsgBlockNum", headerObj.Number().String()). Msg("[OnAnnounce] VRF verification error") return false } - if !bytes.Equal(hash[:], headerObj.Vrf[:32]) { + if !bytes.Equal(hash[:], headerObj.Vrf()[:32]) { consensus.getLogger().Warn(). - Str("MsgBlockNum", headerObj.Number.String()). + Str("MsgBlockNum", headerObj.Number().String()). Msg("[OnAnnounce] VRF proof is not valid") return false } - vrfBlockNumbers, _ := consensus.ChainReader.ReadEpochVrfBlockNums(headerObj.Epoch) + vrfBlockNumbers, _ := consensus.ChainReader.ReadEpochVrfBlockNums(headerObj.Epoch()) consensus.getLogger().Info(). - Str("MsgBlockNum", headerObj.Number.String()). + Str("MsgBlockNum", headerObj.Number().String()). Int("Number of VRF", len(vrfBlockNumbers)). Msg("[OnAnnounce] validated a new VRF") @@ -1253,7 +1253,7 @@ func (consensus *Consensus) GenerateVdfAndProof(newBlock *types.Block, vrfBlockN consensus.getLogger().Info(). Uint64("MsgBlockNum", newBlock.NumberU64()). - Uint64("Epoch", newBlock.Header().Epoch.Uint64()). + Uint64("Epoch", newBlock.Header().Epoch().Uint64()). Int("Num of VRF", len(vrfBlockNumbers)). Msg("[ConsensusMainLoop] VDF computation started") @@ -1277,11 +1277,11 @@ func (consensus *Consensus) GenerateVdfAndProof(newBlock *types.Block, vrfBlockN } // ValidateVdfAndProof validates the VDF/proof in the current epoch -func (consensus *Consensus) ValidateVdfAndProof(headerObj block.Header) bool { - vrfBlockNumbers, err := consensus.ChainReader.ReadEpochVrfBlockNums(headerObj.Epoch) +func (consensus *Consensus) ValidateVdfAndProof(headerObj *block.Header) bool { + vrfBlockNumbers, err := consensus.ChainReader.ReadEpochVrfBlockNums(headerObj.Epoch()) if err != nil { consensus.getLogger().Error().Err(err). - Str("MsgBlockNum", headerObj.Number.String()). + Str("MsgBlockNum", headerObj.Number().String()). Msg("[OnAnnounce] failed to read VRF block numbers for VDF computation") } @@ -1301,17 +1301,17 @@ func (consensus *Consensus) ValidateVdfAndProof(headerObj block.Header) bool { vdfObject := vdf_go.New(core.ShardingSchedule.VdfDifficulty(), seed) vdfOutput := [516]byte{} - copy(vdfOutput[:], headerObj.Vdf) + copy(vdfOutput[:], headerObj.Vdf()) if vdfObject.Verify(vdfOutput) { consensus.getLogger().Info(). - Str("MsgBlockNum", headerObj.Number.String()). + Str("MsgBlockNum", headerObj.Number().String()). Int("Num of VRF", consensus.VdfSeedSize()). Msg("[OnAnnounce] validated a new VDF") } else { consensus.getLogger().Warn(). - Str("MsgBlockNum", headerObj.Number.String()). - Uint64("Epoch", headerObj.Epoch.Uint64()). + Str("MsgBlockNum", headerObj.Number().String()). + Uint64("Epoch", headerObj.Epoch().Uint64()). Int("Num of VRF", consensus.VdfSeedSize()). Msg("[OnAnnounce] VDF proof is not valid") return false diff --git a/contracts/contract_caller.go b/contracts/contract_caller.go index 78bf908b6..577a5cd12 100644 --- a/contracts/contract_caller.go +++ b/contracts/contract_caller.go @@ -33,7 +33,7 @@ func NewContractCaller(bc *core.BlockChain, config *params.ChainConfig) *Contrac // CallContract calls a contracts with the specified transaction. func (cc *ContractCaller) CallContract(tx *types.Transaction) ([]byte, error) { currBlock := cc.blockchain.CurrentBlock() - msg, err := tx.AsMessage(types.MakeSigner(cc.config, currBlock.Header().Epoch)) + msg, err := tx.AsMessage(types.MakeSigner(cc.config, currBlock.Header().Epoch())) if err != nil { utils.GetLogInstance().Error("[ABI] Failed to convert transaction to message", "error", err) return []byte{}, err diff --git a/core/block_validator.go b/core/block_validator.go index 5b86d2ea3..a7840866a 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -69,8 +69,8 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { //if err := v.engine.VerifyUncles(v.bc, block); err != nil { // return err //} - if hash := types.DeriveSha(block.Transactions()); hash != header.TxHash { - return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash) + if hash := types.DeriveSha(block.Transactions()); hash != header.TxHash() { + return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash()) } return nil } @@ -87,24 +87,24 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat // 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 { - return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) + if rbloom != header.Bloom() { + return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom(), rbloom) } // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]])) receiptSha := types.DeriveSha(receipts) - if receiptSha != header.ReceiptHash { - return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) + if receiptSha != header.ReceiptHash() { + return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash(), receiptSha) } cxsSha := types.DeriveMultipleShardsSha(cxReceipts) - if cxsSha != header.OutgoingReceiptHash { - return fmt.Errorf("invalid cross shard receipt root hash (remote: %x local: %x)", header.OutgoingReceiptHash, cxsSha) + if cxsSha != header.OutgoingReceiptHash() { + return fmt.Errorf("invalid cross shard receipt root hash (remote: %x local: %x)", header.OutgoingReceiptHash(), cxsSha) } // Validate the state root against the received state root and throw // an error if they don't match. - if root := statedb.IntermediateRoot(v.config.IsS3(header.Epoch)); header.Root != root { - return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) + if root := statedb.IntermediateRoot(v.config.IsS3(header.Epoch())); header.Root() != root { + return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root(), root) } return nil } @@ -114,14 +114,14 @@ func VerifyBlockLastCommitSigs(bc *BlockChain, block *types.Block) error { header := block.Header() parentBlock := bc.GetBlockByNumber(block.NumberU64() - 1) if parentBlock == nil { - return ctxerror.New("[VerifyNewBlock] Failed to get parent block", "shardID", header.ShardID, "blockNum", header.Number) + return ctxerror.New("[VerifyNewBlock] Failed to get parent block", "shardID", header.ShardID(), "blockNum", header.Number()) } parentHeader := parentBlock.Header() - shardState, err := bc.ReadShardState(parentHeader.Epoch) - committee := shardState.FindCommitteeByID(parentHeader.ShardID) + shardState, err := bc.ReadShardState(parentHeader.Epoch()) + committee := shardState.FindCommitteeByID(parentHeader.ShardID()) if err != nil || committee == nil { - return ctxerror.New("[VerifyNewBlock] Failed to read shard state for cross link header", "shardID", header.ShardID, "blockNum", header.Number).WithCause(err) + return ctxerror.New("[VerifyNewBlock] Failed to read shard state for cross link header", "shardID", header.ShardID(), "blockNum", header.Number()).WithCause(err) } var committerKeys []*bls.PublicKey @@ -136,28 +136,30 @@ func VerifyBlockLastCommitSigs(bc *BlockChain, block *types.Block) error { committerKeys = append(committerKeys, committerKey) } if !parseKeysSuccess { - return ctxerror.New("[VerifyNewBlock] cannot convert BLS public key", "shardID", header.ShardID, "blockNum", header.Number).WithCause(err) + return ctxerror.New("[VerifyNewBlock] cannot convert BLS public key", "shardID", header.ShardID(), "blockNum", header.Number()).WithCause(err) } mask, err := bls2.NewMask(committerKeys, nil) if err != nil { - return ctxerror.New("[VerifyNewBlock] cannot create group sig mask", "shardID", header.ShardID, "blockNum", header.Number).WithCause(err) + return ctxerror.New("[VerifyNewBlock] cannot create group sig mask", "shardID", header.ShardID(), "blockNum", header.Number()).WithCause(err) } - if err := mask.SetMask(header.LastCommitBitmap); err != nil { - return ctxerror.New("[VerifyNewBlock] cannot set group sig mask bits", "shardID", header.ShardID, "blockNum", header.Number).WithCause(err) + if err := mask.SetMask(header.LastCommitBitmap()); err != nil { + return ctxerror.New("[VerifyNewBlock] cannot set group sig mask bits", "shardID", header.ShardID(), "blockNum", header.Number()).WithCause(err) } aggSig := bls.Sign{} - err = aggSig.Deserialize(header.LastCommitSignature[:]) + lastCommitSig := header.LastCommitSignature() + err = aggSig.Deserialize(lastCommitSig[:]) if err != nil { return ctxerror.New("[VerifyNewBlock] unable to deserialize multi-signature from payload").WithCause(err) } blockNumBytes := make([]byte, 8) - binary.LittleEndian.PutUint64(blockNumBytes, header.Number.Uint64()-1) - commitPayload := append(blockNumBytes, header.ParentHash[:]...) + binary.LittleEndian.PutUint64(blockNumBytes, header.Number().Uint64()-1) + parentHash := header.ParentHash() + commitPayload := append(blockNumBytes, parentHash[:]...) if !aggSig.VerifyHash(mask.AggregatePublic, commitPayload) { - return ctxerror.New("[VerifyNewBlock] Failed to verify the signature for last commit sig", "shardID", header.ShardID, "blockNum", header.Number) + return ctxerror.New("[VerifyNewBlock] Failed to verify the signature for last commit sig", "shardID", header.ShardID(), "blockNum", header.Number()) } return nil } diff --git a/core/blockchain.go b/core/blockchain.go index 5f9d6f64b..2307c4cdd 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -259,7 +259,7 @@ func IsEpochLastBlock(block *types.Block) bool { // IsEpochLastBlockByHeader returns whether this block is the last block of an epoch // given block header func IsEpochLastBlockByHeader(header *block.Header) bool { - return ShardingSchedule.IsLastBlock(header.Number.Uint64()) + return ShardingSchedule.IsLastBlock(header.Number().Uint64()) } func (bc *BlockChain) getProcInterrupt() bool { @@ -317,15 +317,15 @@ func (bc *BlockChain) loadLastState() error { // Issue a status log for the user currentFastBlock := bc.CurrentFastBlock() - headerTd := bc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()) + headerTd := bc.GetTd(currentHeader.Hash(), currentHeader.Number().Uint64()) blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) fastTd := bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64()) utils.Logger().Info(). - Str("number", currentHeader.Number.String()). + Str("number", currentHeader.Number().String()). Str("hash", currentHeader.Hash().Hex()). Str("td", headerTd.String()). - Str("age", common.PrettyAge(time.Unix(currentHeader.Time.Int64(), 0)).String()). + Str("age", common.PrettyAge(time.Unix(currentHeader.Time().Int64(), 0)).String()). Msg("Loaded most recent local header") utils.Logger().Info(). Str("number", currentBlock.Number().String()). @@ -369,8 +369,8 @@ func (bc *BlockChain) SetHead(head uint64) error { bc.shardStateCache.Purge() // Rewind the block chain, ensuring we don't end up with a stateless head block - if currentBlock := bc.CurrentBlock(); currentBlock != nil && currentHeader.Number.Uint64() < currentBlock.NumberU64() { - bc.currentBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64())) + if currentBlock := bc.CurrentBlock(); currentBlock != nil && currentHeader.Number().Uint64() < currentBlock.NumberU64() { + bc.currentBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number().Uint64())) } if currentBlock := bc.CurrentBlock(); currentBlock != nil { if _, err := state.New(currentBlock.Root(), bc.stateCache); err != nil { @@ -379,8 +379,8 @@ func (bc *BlockChain) SetHead(head uint64) error { } } // Rewind the fast block in a simpleton way to the target head - if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock != nil && currentHeader.Number.Uint64() < currentFastBlock.NumberU64() { - bc.currentFastBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64())) + if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock != nil && currentHeader.Number().Uint64() < currentFastBlock.NumberU64() { + bc.currentFastBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number().Uint64())) } // If either blocks reached nil, reset to the genesis state if currentBlock := bc.CurrentBlock(); currentBlock == nil { @@ -833,7 +833,7 @@ func (bc *BlockChain) Rollback(chain []common.Hash) { currentHeader := bc.hc.CurrentHeader() if currentHeader != nil && currentHeader.Hash() == hash { - bc.hc.SetCurrentHeader(bc.GetHeader(currentHeader.ParentHash, currentHeader.Number.Uint64()-1)) + bc.hc.SetCurrentHeader(bc.GetHeader(currentHeader.ParentHash(), currentHeader.Number().Uint64()-1)) } if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock != nil && currentFastBlock.Hash() == hash { newFastBlock := bc.GetBlock(currentFastBlock.ParentHash(), currentFastBlock.NumberU64()-1) @@ -1040,7 +1040,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. } // Find the next state trie we need to commit header := bc.GetHeaderByNumber(current - triesInMemory) - chosen := header.Number.Uint64() + chosen := header.Number().Uint64() // If we exceeded out time allowance, flush an entire trie to disk if bc.gcproc > bc.cacheConfig.TrieTimeLimit { @@ -1054,7 +1054,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. Msg("State in memory for too long, committing") } // Flush an entire trie and restart the counters - triedb.Commit(header.Root, true) + triedb.Commit(header.Root(), true) lastWrite = chosen bc.gcproc = 0 } @@ -1074,7 +1074,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. batch := bc.db.NewBatch() rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts) - epoch := block.Header().Epoch + epoch := block.Header().Epoch() shardingConfig := ShardingSchedule.InstanceForEpoch(epoch) shardNum := int(shardingConfig.NumShards()) for i := 0; i < shardNum; i++ { @@ -1137,13 +1137,13 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) { header := block.Header() header.Logger(utils.Logger()).Info(). Int("segmentIndex", idx). - Str("parentHash", header.ParentHash.Hex()). + Str("parentHash", header.ParentHash().Hex()). Msg("added block to chain") // TODO: move into WriteBlockWithState - if header.ShardStateHash != (common.Hash{}) { - epoch := new(big.Int).Add(header.Epoch, common.Big1) - err = bc.WriteShardStateBytes(epoch, header.ShardState) + if header.ShardStateHash() != (common.Hash{}) { + epoch := new(big.Int).Add(header.Epoch(), common.Big1) + err = bc.WriteShardStateBytes(epoch, header.ShardState()) if err != nil { header.Logger(utils.Logger()).Warn().Err(err).Msg("cannot store shard state") return n, err @@ -1151,9 +1151,9 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) { } // TODO: move into WriteBlockWithState - if len(header.CrossLinks) > 0 { + if len(header.CrossLinks()) > 0 { crossLinks := &types.CrossLinks{} - err = rlp.DecodeBytes(header.CrossLinks, crossLinks) + err = rlp.DecodeBytes(header.CrossLinks(), crossLinks) if err != nil { header.Logger(utils.Logger()).Warn().Err(err).Msg("[insertChain] cannot parse cross links") return n, err @@ -1373,19 +1373,19 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty //check non zero VRF field in header and add to local db if len(block.Vrf()) > 0 { - vrfBlockNumbers, _ := bc.ReadEpochVrfBlockNums(block.Header().Epoch) + vrfBlockNumbers, _ := bc.ReadEpochVrfBlockNums(block.Header().Epoch()) if (len(vrfBlockNumbers) > 0) && (vrfBlockNumbers[len(vrfBlockNumbers)-1] == block.NumberU64()) { utils.Logger().Error(). Str("number", chain[i].Number().String()). - Str("epoch", block.Header().Epoch.String()). + Str("epoch", block.Header().Epoch().String()). Msg("VRF block number is already in local db") } else { vrfBlockNumbers = append(vrfBlockNumbers, block.NumberU64()) - err = bc.WriteEpochVrfBlockNums(block.Header().Epoch, vrfBlockNumbers) + err = bc.WriteEpochVrfBlockNums(block.Header().Epoch(), vrfBlockNumbers) if err != nil { utils.Logger().Error(). Str("number", chain[i].Number().String()). - Str("epoch", block.Header().Epoch.String()). + Str("epoch", block.Header().Epoch().String()). Msg("failed to write VRF block number to local db") } } @@ -1393,11 +1393,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty //check non zero Vdf in header and add to local db if len(block.Vdf()) > 0 { - err = bc.WriteEpochVdfBlockNum(block.Header().Epoch, block.Number()) + err = bc.WriteEpochVdfBlockNum(block.Header().Epoch(), block.Number()) if err != nil { utils.Logger().Error(). Str("number", chain[i].Number().String()). - Str("epoch", block.Header().Epoch.String()). + Str("epoch", block.Header().Epoch().String()). Msg("failed to write VDF block number to local db") } } @@ -1890,7 +1890,7 @@ func (bc *BlockChain) GetVdfByNumber(number uint64) []byte { return []byte{} } - return header.Vdf + return header.Vdf() } // GetVrfByNumber retrieves the randomness preimage given the block number, return 0 if not exist @@ -1899,7 +1899,7 @@ func (bc *BlockChain) GetVrfByNumber(number uint64) []byte { if header == nil { return []byte{} } - return header.Vrf + return header.Vrf() } // GetShardState returns the shard state for the given epoch, @@ -2125,14 +2125,14 @@ func (bc *BlockChain) WriteCXReceipts(shardID uint32, blockNum uint64, blockHash // CXMerkleProof calculates the cross shard transaction merkle proof of a given destination shard func (bc *BlockChain) CXMerkleProof(shardID uint32, block *types.Block) (*types.CXMerkleProof, error) { - proof := &types.CXMerkleProof{BlockNum: block.Number(), BlockHash: block.Hash(), ShardID: block.ShardID(), CXReceiptHash: block.Header().OutgoingReceiptHash, CXShardHashes: []common.Hash{}, ShardIDs: []uint32{}} + proof := &types.CXMerkleProof{BlockNum: block.Number(), BlockHash: block.Hash(), ShardID: block.ShardID(), CXReceiptHash: block.Header().OutgoingReceiptHash(), CXShardHashes: []common.Hash{}, ShardIDs: []uint32{}} cxs, err := rawdb.ReadCXReceipts(bc.db, shardID, block.NumberU64(), block.Hash(), false) if err != nil || cxs == nil { return nil, err } - epoch := block.Header().Epoch + epoch := block.Header().Epoch() shardingConfig := ShardingSchedule.InstanceForEpoch(epoch) shardNum := int(shardingConfig.NumShards()) diff --git a/core/chain_indexer.go b/core/chain_indexer.go index 038e13e5d..8371f48d7 100644 --- a/core/chain_indexer.go +++ b/core/chain_indexer.go @@ -200,7 +200,7 @@ func (c *ChainIndexer) eventLoop(currentHeader *block.Header, events chan ChainH defer sub.Unsubscribe() // Fire the initial new head event to start any outstanding processing - c.newHead(currentHeader.Number.Uint64(), false) + c.newHead(currentHeader.Number().Uint64(), false) var ( prevHeader = currentHeader @@ -221,17 +221,17 @@ func (c *ChainIndexer) eventLoop(currentHeader *block.Header, events chan ChainH return } header := ev.Block.Header() - if header.ParentHash != prevHash { + if header.ParentHash() != prevHash { // Reorg to the common ancestor if needed (might not exist in light sync mode, skip reorg then) // TODO(karalabe, zsfelfoldi): This seems a bit brittle, can we detect this case explicitly? - if rawdb.ReadCanonicalHash(c.chainDb, prevHeader.Number.Uint64()) != prevHash { + if rawdb.ReadCanonicalHash(c.chainDb, prevHeader.Number().Uint64()) != prevHash { if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, header); h != nil { - c.newHead(h.Number.Uint64(), true) + c.newHead(h.Number().Uint64(), true) } } } - c.newHead(header.Number.Uint64(), false) + c.newHead(header.Number().Uint64(), false) prevHeader, prevHash = header, header.Hash() } @@ -404,7 +404,7 @@ func (c *ChainIndexer) processSection(section uint64, lastHead common.Hash) (com header := rawdb.ReadHeader(c.chainDb, hash, number) if header == nil { return common.Hash{}, fmt.Errorf("block #%d [%x…] not found", number, hash[:4]) - } else if header.ParentHash != lastHead { + } else if header.ParentHash() != lastHead { return common.Hash{}, fmt.Errorf("chain reorged during section processing") } if err := c.backend.Process(c.ctx, header); err != nil { diff --git a/core/chain_makers.go b/core/chain_makers.go index a85bbe8da..2e45407f1 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -59,18 +59,18 @@ func (b *BlockGen) SetCoinbase(addr common.Address) { } panic("coinbase can only be set once") } - b.header.Coinbase = addr - b.gasPool = new(GasPool).AddGas(b.header.GasLimit) + b.header.SetCoinbase(addr) + b.gasPool = new(GasPool).AddGas(b.header.GasLimit()) } // SetExtra sets the extra data field of the generated block. func (b *BlockGen) SetExtra(data []byte) { - b.header.Extra = data + b.header.SetExtra(data) } // SetShardID sets the shardID field of the generated block. func (b *BlockGen) SetShardID(shardID uint32) { - b.header.ShardID = shardID + b.header.SetShardID(shardID) } // AddTx adds a transaction to the generated block. If no coinbase has @@ -98,7 +98,11 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { b.SetCoinbase(common.Address{}) } b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) - receipt, _, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) + coinbase := b.header.Coinbase() + gasUsed := b.header.GasUsed() + receipt, _, _, err := ApplyTransaction(b.config, bc, &coinbase, b.gasPool, b.statedb, b.header, tx, &gasUsed, vm.Config{}) + b.header.SetGasUsed(gasUsed) + b.header.SetCoinbase(coinbase) if err != nil { panic(err) } @@ -108,7 +112,7 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { // Number returns the block number of the block being generated. func (b *BlockGen) Number() *big.Int { - return new(big.Int).Set(b.header.Number) + return b.header.Number() } // AddUncheckedReceipt forcefully adds a receipts to the block without a @@ -184,7 +188,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse } // Write state changes to db - root, err := statedb.Commit(config.IsS3(b.header.Epoch)) + root, err := statedb.Commit(config.IsS3(b.header.Epoch())) if err != nil { panic(fmt.Sprintf("state write error: %v", err)) } @@ -216,20 +220,15 @@ func makeHeader(chain consensus_engine.ChainReader, parent *types.Block, state * time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds } - return &block.Header{ - Root: state.IntermediateRoot(chain.Config().IsS3(parent.Epoch())), - ParentHash: parent.Hash(), - Coinbase: parent.Coinbase(), - //Difficulty: engine.CalcDifficulty(chain, time.Uint64(), &types.Header{ - // Number: parent.Number(), - // Time: new(big.Int).Sub(time, big.NewInt(10)), - // Difficulty: parent.Difficulty(), - // UncleHash: parent.UncleHash(), - //}), - GasLimit: CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()), - Number: new(big.Int).Add(parent.Number(), common.Big1), - Time: time, - } + return block.NewHeaderWith(). + Root(state.IntermediateRoot(chain.Config().IsS3(parent.Epoch()))). + ParentHash(parent.Hash()). + Coinbase(parent.Coinbase()). + GasLimit(CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit())). + Number(new(big.Int).Add(parent.Number(), common.Big1)). + Epoch(parent.Epoch()). + Time(time). + Header() } // makeHeaderChain creates a deterministic chain of headers rooted at parent. diff --git a/core/core_test.go b/core/core_test.go index 9870b6f06..2c32f2ff7 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -10,13 +10,13 @@ import ( ) func TestIsEpochBlock(t *testing.T) { - block1 := types.NewBlock(&block.Header{Number: big.NewInt(10)}, nil, nil, nil, nil) - block2 := types.NewBlock(&block.Header{Number: big.NewInt(0)}, nil, nil, nil, nil) - block3 := types.NewBlock(&block.Header{Number: big.NewInt(344064)}, nil, nil, nil, nil) - block4 := types.NewBlock(&block.Header{Number: big.NewInt(77)}, nil, nil, nil, nil) - block5 := types.NewBlock(&block.Header{Number: big.NewInt(78)}, nil, nil, nil, nil) - block6 := types.NewBlock(&block.Header{Number: big.NewInt(188)}, nil, nil, nil, nil) - block7 := types.NewBlock(&block.Header{Number: big.NewInt(189)}, nil, nil, nil, nil) + block1 := types.NewBlock(block.NewHeaderWith().Number(big.NewInt(10)).Header(), nil, nil, nil, nil) + block2 := types.NewBlock(block.NewHeaderWith().Number(big.NewInt(0)).Header(), nil, nil, nil, nil) + block3 := types.NewBlock(block.NewHeaderWith().Number(big.NewInt(344064)).Header(), nil, nil, nil, nil) + block4 := types.NewBlock(block.NewHeaderWith().Number(big.NewInt(77)).Header(), nil, nil, nil, nil) + block5 := types.NewBlock(block.NewHeaderWith().Number(big.NewInt(78)).Header(), nil, nil, nil, nil) + block6 := types.NewBlock(block.NewHeaderWith().Number(big.NewInt(188)).Header(), nil, nil, nil, nil) + block7 := types.NewBlock(block.NewHeaderWith().Number(big.NewInt(189)).Header(), nil, nil, nil, nil) tests := []struct { schedule shardingconfig.Schedule block *types.Block diff --git a/core/evm.go b/core/evm.go index f39b1218f..37ed3fc5f 100644 --- a/core/evm.go +++ b/core/evm.go @@ -52,10 +52,10 @@ func NewEVMContext(msg Message, header *block.Header, chain ChainContext, author GetHash: GetHashFn(header, chain), Origin: msg.From(), Coinbase: beneficiary, - BlockNumber: new(big.Int).Set(header.Number), - EpochNumber: new(big.Int).Set(header.Epoch), - Time: new(big.Int).Set(header.Time), - GasLimit: header.GasLimit, + BlockNumber: header.Number(), + EpochNumber: header.Epoch(), + Time: header.Time(), + GasLimit: header.GasLimit(), GasPrice: new(big.Int).Set(msg.GasPrice()), } } @@ -68,7 +68,7 @@ func GetHashFn(ref *block.Header, chain ChainContext) func(n uint64) common.Hash // If there's no hash cache yet, make one if cache == nil { cache = map[uint64]common.Hash{ - ref.Number.Uint64() - 1: ref.ParentHash, + ref.Number().Uint64() - 1: ref.ParentHash(), } } // Try to fulfill the request from the cache @@ -76,10 +76,10 @@ func GetHashFn(ref *block.Header, chain ChainContext) func(n uint64) common.Hash return hash } // Not cached, iterate the blocks and cache the hashes - for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) { - cache[header.Number.Uint64()-1] = header.ParentHash - if n == header.Number.Uint64()-1 { - return header.ParentHash + for header := chain.GetHeader(ref.ParentHash(), ref.Number().Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash(), header.Number().Uint64()-1) { + cache[header.Number().Uint64()-1] = header.ParentHash() + if n == header.Number().Uint64()-1 { + return header.ParentHash() } } return common.Hash{} diff --git a/core/genesis.go b/core/genesis.go index ce9e65ce3..ae9d55688 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -245,21 +245,21 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { utils.Logger().Error().Msg("failed to rlp-serialize genesis shard state") os.Exit(1) } - head := &block.Header{ - Number: new(big.Int).SetUint64(g.Number), - Epoch: big.NewInt(0), - ShardID: g.ShardID, - Time: new(big.Int).SetUint64(g.Timestamp), - ParentHash: g.ParentHash, - Extra: g.ExtraData, - GasLimit: g.GasLimit, - GasUsed: g.GasUsed, - MixDigest: g.Mixhash, - Coinbase: g.Coinbase, - Root: root, - ShardStateHash: g.ShardStateHash, - ShardState: shardStateBytes, - } + head := block.NewHeaderWith(). + Number(new(big.Int).SetUint64(g.Number)). + Epoch(big.NewInt(0)). + ShardID(g.ShardID). + Time(new(big.Int).SetUint64(g.Timestamp)). + ParentHash(g.ParentHash). + Extra(g.ExtraData). + GasLimit(g.GasLimit). + GasUsed(g.GasUsed). + MixDigest(g.Mixhash). + Coinbase(g.Coinbase). + Root(root). + ShardStateHash(g.ShardStateHash). + ShardState(shardStateBytes). + Header() statedb.Commit(false) statedb.Database().TrieDB().Commit(root, true) @@ -280,7 +280,7 @@ func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { rawdb.WriteHeadBlockHash(db, block.Hash()) rawdb.WriteHeadHeaderHash(db, block.Hash()) - err := rawdb.WriteShardStateBytes(db, block.Header().Epoch, block.Header().ShardState) + err := rawdb.WriteShardStateBytes(db, block.Header().Epoch(), block.Header().ShardState()) if err != nil { utils.Logger().Error().Err(err).Msg("Failed to store genesis shard state") diff --git a/core/headerchain.go b/core/headerchain.go index 17dcd4c42..035225825 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -137,7 +137,7 @@ func (hc *HeaderChain) WriteHeader(header *block.Header) (status WriteStatus, er // Cache some values to prevent constant recalculation var ( hash = header.Hash() - number = header.Number.Uint64() + number = header.Number().Uint64() ) // TODO: implement fork choice mechanism //localTd := hc.GetTd(hc.currentHeaderHash, hc.CurrentHeader().Number.Uint64()) @@ -206,18 +206,19 @@ type WhCallback func(*block.Header) error func (hc *HeaderChain) ValidateHeaderChain(chain []*block.Header, checkFreq int) (int, error) { // Do a sanity check that the provided chain is actually ordered and linked for i := 1; i < len(chain); i++ { - if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() { + parentHash := chain[i].ParentHash() + if chain[i].Number().Uint64() != chain[i-1].Number().Uint64()+1 || parentHash != chain[i-1].Hash() { // Chain broke ancestry, log a message (programming error) and skip insertion utils.Logger().Error(). - Str("number", chain[i].Number.String()). + Str("number", chain[i].Number().String()). Str("hash", chain[i].Hash().Hex()). - Str("parent", chain[i].ParentHash.Hex()). - Str("prevnumber", chain[i-1].Number.String()). + Str("parent", parentHash.Hex()). + Str("prevnumber", chain[i-1].Number().String()). Str("prevhash", chain[i-1].Hash().Hex()). Msg("Non contiguous header insert") - return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].Number, - chain[i-1].Hash().Bytes()[:4], i, chain[i].Number, chain[i].Hash().Bytes()[:4], chain[i].ParentHash[:4]) + return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].Number(), + chain[i-1].Hash().Bytes()[:4], i, chain[i].Number(), chain[i].Hash().Bytes()[:4], parentHash[:4]) } } @@ -271,7 +272,7 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*block.Header, writeHeader WhCa return i, errors.New("aborted") } // If the header's already known, skip it, otherwise store - if hc.HasHeader(header.Hash(), header.Number.Uint64()) { + if hc.HasHeader(header.Hash(), header.Number().Uint64()) { stats.ignored++ continue } @@ -286,10 +287,10 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*block.Header, writeHeader WhCa context := utils.Logger().With(). Int("count", stats.processed). Str("elapsed", common.PrettyDuration(time.Since(start)).String()). - Str("number", last.Number.String()). + Str("number", last.Number().String()). Str("hash", last.Hash().Hex()) - if timestamp := time.Unix(last.Time.Int64(), 0); time.Since(timestamp) > time.Minute { + if timestamp := time.Unix(last.Time().Int64(), 0); time.Since(timestamp) > time.Minute { context = context.Str("age", common.PrettyAge(timestamp).String()) } if stats.ignored > 0 { @@ -312,12 +313,12 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co // Iterate the headers until enough is collected or the genesis reached chain := make([]common.Hash, 0, max) for i := uint64(0); i < max; i++ { - next := header.ParentHash - if header = hc.GetHeader(next, header.Number.Uint64()-1); header == nil { + next := header.ParentHash() + if header = hc.GetHeader(next, header.Number().Uint64()-1); header == nil { break } chain = append(chain, next) - if header.Number.Sign() == 0 { + if header.Number().Sign() == 0 { break } } @@ -336,7 +337,7 @@ func (hc *HeaderChain) GetAncestor(hash common.Hash, number, ancestor uint64, ma if ancestor == 1 { // in this case it is cheaper to just read the header if header := hc.GetHeader(hash, number); header != nil { - return header.ParentHash, number - 1 + return header.ParentHash(), number - 1 } return common.Hash{}, 0 } @@ -354,7 +355,7 @@ func (hc *HeaderChain) GetAncestor(hash common.Hash, number, ancestor uint64, ma if header == nil { return common.Hash{}, 0 } - hash = header.ParentHash + hash = header.ParentHash() number-- } return hash, number @@ -462,19 +463,19 @@ func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) { height := uint64(0) if hdr := hc.CurrentHeader(); hdr != nil { - height = hdr.Number.Uint64() + height = hdr.Number().Uint64() } batch := hc.chainDb.NewBatch() - for hdr := hc.CurrentHeader(); hdr != nil && hdr.Number.Uint64() > head; hdr = hc.CurrentHeader() { + for hdr := hc.CurrentHeader(); hdr != nil && hdr.Number().Uint64() > head; hdr = hc.CurrentHeader() { hash := hdr.Hash() - num := hdr.Number.Uint64() + num := hdr.Number().Uint64() if delFn != nil { delFn(batch, hash, num) } rawdb.DeleteHeader(batch, hash, num) rawdb.DeleteTd(batch, hash, num) - hc.currentHeader.Store(hc.GetHeader(hdr.ParentHash, hdr.Number.Uint64()-1)) + hc.currentHeader.Store(hc.GetHeader(hdr.ParentHash(), hdr.Number().Uint64()-1)) } // Roll back the canonical chain numbering for i := height; i > head; i-- { diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index b05c5c044..a07c438ae 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -171,7 +171,7 @@ func WriteHeader(db DatabaseWriter, header *block.Header) { // Write the hash -> number mapping var ( hash = header.Hash() - number = header.Number.Uint64() + number = header.Number().Uint64() encoded = encodeBlockNumber(number) ) key := headerNumberKey(hash) @@ -349,12 +349,11 @@ func WriteBlock(db DatabaseWriter, block *types.Block) { WriteBody(db, block.Hash(), block.NumberU64(), block.Body()) WriteHeader(db, block.Header()) // TODO ek – maybe roll the below into WriteHeader() - epoch := block.Header().Epoch + epoch := block.Header().Epoch() if epoch == nil { // backward compatibility return } - epoch = new(big.Int).Set(epoch) epochBlockNum := block.Number() writeOne := func() { if err := WriteEpochBlockNumber(db, epoch, epochBlockNum); err != nil { @@ -368,7 +367,7 @@ func WriteBlock(db DatabaseWriter, block *types.Block) { } // TODO: don't change epoch based on shard state presence - if len(block.Header().ShardState) > 0 && block.NumberU64() != 0 { + if len(block.Header().ShardState()) > 0 && block.NumberU64() != 0 { // End-of-epoch block; record the next epoch after this block. epoch = new(big.Int).Add(epoch, common.Big1) epochBlockNum = new(big.Int).Add(epochBlockNum, common.Big1) @@ -386,24 +385,24 @@ func DeleteBlock(db DatabaseDeleter, hash common.Hash, number uint64) { // FindCommonAncestor returns the last common ancestor of two block headers func FindCommonAncestor(db DatabaseReader, a, b *block.Header) *block.Header { - for bn := b.Number.Uint64(); a.Number.Uint64() > bn; { - a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1) + for bn := b.Number().Uint64(); a.Number().Uint64() > bn; { + a = ReadHeader(db, a.ParentHash(), a.Number().Uint64()-1) if a == nil { return nil } } - for an := a.Number.Uint64(); an < b.Number.Uint64(); { - b = ReadHeader(db, b.ParentHash, b.Number.Uint64()-1) + for an := a.Number().Uint64(); an < b.Number().Uint64(); { + b = ReadHeader(db, b.ParentHash(), b.Number().Uint64()-1) if b == nil { return nil } } for a.Hash() != b.Hash() { - a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1) + a = ReadHeader(db, a.ParentHash(), a.Number().Uint64()-1) if a == nil { return nil } - b = ReadHeader(db, b.ParentHash, b.Number.Uint64()-1) + b = ReadHeader(db, b.ParentHash(), b.Number().Uint64()-1) if b == nil { return nil } diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index e8729ab6b..a8e3cf2f9 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -40,18 +40,18 @@ func TestHeaderStorage(t *testing.T) { db := ethdb.NewMemDatabase() // Create a test header to move around the database and make sure it's really new - header := &block.Header{Number: big.NewInt(42), Extra: []byte("test header")} - if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { + header := block.NewHeaderWith().Number(big.NewInt(42)).Extra([]byte("test header")).Header() + if entry := ReadHeader(db, header.Hash(), header.Number().Uint64()); entry != nil { t.Fatalf("Non existent header returned: %v", entry) } // Write and verify the header in the database WriteHeader(db, header) - if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry == nil { + if entry := ReadHeader(db, header.Hash(), header.Number().Uint64()); entry == nil { t.Fatalf("Stored header not found") } else if entry.Hash() != header.Hash() { t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, header) } - if entry := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil { + if entry := ReadHeaderRLP(db, header.Hash(), header.Number().Uint64()); entry == nil { t.Fatalf("Stored header RLP not found") } else { hasher := sha3.NewLegacyKeccak256() @@ -62,8 +62,8 @@ func TestHeaderStorage(t *testing.T) { } } // Delete the header and verify the execution - DeleteHeader(db, header.Hash(), header.Number.Uint64()) - if entry := ReadHeader(db, header.Hash(), header.Number.Uint64()); entry != nil { + DeleteHeader(db, header.Hash(), header.Number().Uint64()) + if entry := ReadHeader(db, header.Hash(), header.Number().Uint64()); entry != nil { t.Fatalf("Deleted header returned: %v", entry) } } @@ -73,7 +73,7 @@ func TestBodyStorage(t *testing.T) { db := ethdb.NewMemDatabase() // Create a test body to move around the database and make sure it's really new - body := &types.Body{Uncles: []*block.Header{{Extra: []byte("test header")}}} + body := &types.Body{Uncles: []*block.Header{block.NewHeaderWith().Extra([]byte("test header")).Header()}} hasher := sha3.NewLegacyKeccak256() rlp.Encode(hasher, body) @@ -111,14 +111,14 @@ func TestBlockStorage(t *testing.T) { db := ethdb.NewMemDatabase() // Create a test block to move around the database and make sure it's really new - block := types.NewBlockWithHeader(&block.Header{ - Extra: []byte("test block"), - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, - Epoch: big.NewInt(0), - Number: big.NewInt(0), - ShardState: []byte("dummy data"), - }) + block := types.NewBlockWithHeader(block.NewHeaderWith(). + Extra([]byte("test block")). + TxHash(types.EmptyRootHash). + ReceiptHash(types.EmptyRootHash). + Epoch(big.NewInt(0)). + Number(big.NewInt(0)). + ShardState([]byte("dummy data")). + Header()) if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { t.Fatalf("Non existent block returned: %v", entry) } @@ -171,11 +171,11 @@ func TestBlockStorage(t *testing.T) { // Tests that partial block contents don't get reassembled into full blocks. func TestPartialBlockStorage(t *testing.T) { db := ethdb.NewMemDatabase() - block := types.NewBlockWithHeader(&block.Header{ - Extra: []byte("test block"), - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, - }) + block := types.NewBlockWithHeader(block.NewHeaderWith(). + Extra([]byte("test block")). + TxHash(types.EmptyRootHash). + ReceiptHash(types.EmptyRootHash). + Header()) // Store a header and check that it's not recognized as a block WriteHeader(db, block.Header()) if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { @@ -251,9 +251,9 @@ func TestCanonicalMappingStorage(t *testing.T) { func TestHeadStorage(t *testing.T) { db := ethdb.NewMemDatabase() - blockHead := types.NewBlockWithHeader(&block.Header{Extra: []byte("test block header")}) - blockFull := types.NewBlockWithHeader(&block.Header{Extra: []byte("test block full")}) - blockFast := types.NewBlockWithHeader(&block.Header{Extra: []byte("test block fast")}) + blockHead := types.NewBlockWithHeader(block.NewHeaderWith().Extra([]byte("test block header")).Header()) + blockFull := types.NewBlockWithHeader(block.NewHeaderWith().Extra([]byte("test block full")).Header()) + blockFast := types.NewBlockWithHeader(block.NewHeaderWith().Extra([]byte("test block fast")).Header()) // Check that no head entries are in a pristine database if entry := ReadHeadHeaderHash(db); entry != (common.Hash{}) { diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index 7c1acb529..bb2e1f152 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -36,7 +36,7 @@ func TestLookupStorage(t *testing.T) { tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), 0, big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}) txs := []*types.Transaction{tx1, tx2, tx3} - block := types.NewBlock(&block2.Header{Number: big.NewInt(314)}, txs, nil, nil, nil) + block := types.NewBlock(block2.NewHeaderWith().Number(big.NewInt(314)).Header(), txs, nil, nil, nil) // Check that no transactions entries are in a pristine database for i, tx := range txs { diff --git a/core/state_processor.go b/core/state_processor.go index c3550e11e..3fa05ffc1 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -66,7 +66,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.DB, cfg vm.C incxs = block.IncomingReceipts() usedGas = new(uint64) header = block.Header() - coinbase = block.Header().Coinbase + coinbase = block.Header().Coinbase() allLogs []*types.Log gp = new(GasPool).AddGas(block.GasLimit()) ) @@ -104,12 +104,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.DB, cfg vm.C // return true if it is valid func getTransactionType(header *block.Header, tx *types.Transaction) types.TransactionType { - if tx.ShardID() == tx.ToShardID() && header.ShardID == tx.ShardID() { + if tx.ShardID() == tx.ToShardID() && header.ShardID() == tx.ShardID() { return types.SameShardTx } - numShards := ShardingSchedule.InstanceForEpoch(header.Epoch).NumShards() + numShards := ShardingSchedule.InstanceForEpoch(header.Epoch()).NumShards() // Assuming here all the shards are consecutive from 0 to n-1, n is total number of shards - if tx.ShardID() != tx.ToShardID() && header.ShardID == tx.ShardID() && tx.ToShardID() < numShards { + if tx.ShardID() != tx.ToShardID() && header.ShardID() == tx.ShardID() && tx.ToShardID() < numShards { return types.SubtractionOnly } return types.InvalidTx @@ -124,7 +124,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo if txType == types.InvalidTx { return nil, nil, 0, fmt.Errorf("Invalid Transaction Type") } - msg, err := tx.AsMessage(types.MakeSigner(config, header.Epoch)) + msg, err := tx.AsMessage(types.MakeSigner(config, header.Epoch())) // skip signer err for additiononly tx if err != nil { return nil, nil, 0, err @@ -143,10 +143,10 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo } // Update the state with pending changes var root []byte - if config.IsS3(header.Epoch) { + if config.IsS3(header.Epoch()) { statedb.Finalise(true) } else { - root = statedb.IntermediateRoot(config.IsS3(header.Epoch)).Bytes() + root = statedb.IntermediateRoot(config.IsS3(header.Epoch())).Bytes() } *usedGas += gas @@ -190,7 +190,7 @@ func ApplyIncomingReceipt(config *params.ChainConfig, db *state.DB, header *bloc db.CreateAccount(*cx.To) } db.AddBalance(*cx.To, cx.Amount) - db.IntermediateRoot(config.IsS3(header.Epoch)).Bytes() + db.IntermediateRoot(config.IsS3(header.Epoch())).Bytes() } return nil } diff --git a/core/tx_pool.go b/core/tx_pool.go index e7713f4fd..c1da5ca2e 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -374,10 +374,10 @@ func (pool *TxPool) reset(oldHead, newHead *block.Header) { // If we're reorging an old state, reinject all dropped transactions var reinject types.Transactions - if oldHead != nil && oldHead.Hash() != newHead.ParentHash { + if oldHead != nil && oldHead.Hash() != newHead.ParentHash() { // If the reorg is too deep, avoid doing it (will happen during fast sync) - oldNum := oldHead.Number.Uint64() - newNum := newHead.Number.Uint64() + oldNum := oldHead.Number().Uint64() + newNum := newHead.Number().Uint64() if depth := uint64(math.Abs(float64(oldNum) - float64(newNum))); depth > 64 { utils.Logger().Debug().Uint64("depth", depth).Msg("Skipping deep transaction reorg") @@ -386,14 +386,14 @@ func (pool *TxPool) reset(oldHead, newHead *block.Header) { var discarded, included types.Transactions var ( - rem = pool.chain.GetBlock(oldHead.Hash(), oldHead.Number.Uint64()) - add = pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64()) + rem = pool.chain.GetBlock(oldHead.Hash(), oldHead.Number().Uint64()) + add = pool.chain.GetBlock(newHead.Hash(), newHead.Number().Uint64()) ) for rem.NumberU64() > add.NumberU64() { discarded = append(discarded, rem.Transactions()...) if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { utils.Logger().Error(). - Str("block", oldHead.Number.String()). + Str("block", oldHead.Number().String()). Str("hash", oldHead.Hash().Hex()). Msg("Unrooted old chain seen by tx pool") return @@ -403,7 +403,7 @@ func (pool *TxPool) reset(oldHead, newHead *block.Header) { included = append(included, add.Transactions()...) if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { utils.Logger().Error(). - Str("block", newHead.Number.String()). + Str("block", newHead.Number().String()). Str("hash", newHead.Hash().Hex()). Msg("Unrooted new chain seen by tx pool") return @@ -413,7 +413,7 @@ func (pool *TxPool) reset(oldHead, newHead *block.Header) { discarded = append(discarded, rem.Transactions()...) if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil { utils.Logger().Error(). - Str("block", oldHead.Number.String()). + Str("block", oldHead.Number().String()). Str("hash", oldHead.Hash().Hex()). Msg("Unrooted old chain seen by tx pool") return @@ -421,7 +421,7 @@ func (pool *TxPool) reset(oldHead, newHead *block.Header) { included = append(included, add.Transactions()...) if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil { utils.Logger().Error(). - Str("block", newHead.Number.String()). + Str("block", newHead.Number().String()). Str("hash", newHead.Hash().Hex()). Msg("Unrooted new chain seen by tx pool") return @@ -434,14 +434,14 @@ func (pool *TxPool) reset(oldHead, newHead *block.Header) { if newHead == nil { newHead = pool.chain.CurrentBlock().Header() // Special case during testing } - statedb, err := pool.chain.StateAt(newHead.Root) + statedb, err := pool.chain.StateAt(newHead.Root()) if err != nil { utils.Logger().Error().Err(err).Msg("Failed to reset txpool state") return } pool.currentState = statedb pool.pendingState = state.ManageState(statedb) - pool.currentMaxGas = newHead.GasLimit + pool.currentMaxGas = newHead.GasLimit() // Inject any transactions discarded due to reorgs utils.Logger().Debug().Int("count", len(reinject)).Msg("Reinjecting stale transactions") diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index f0ae49b58..990bc3929 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -54,9 +54,9 @@ type testBlockChain struct { } func (bc *testBlockChain) CurrentBlock() *types.Block { - return types.NewBlock(&block.Header{ - GasLimit: bc.gasLimit, - }, nil, nil, nil, nil) + return types.NewBlock(block.NewHeaderWith(). + GasLimit(bc.gasLimit). + Header(), nil, nil, nil, nil) } func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { diff --git a/core/types/block.go b/core/types/block.go index e3e484d0d..26e3dd98d 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -102,14 +102,16 @@ type Block struct { // SetLastCommitSig sets the last block's commit group signature. func (b *Block) SetLastCommitSig(sig []byte, signers []byte) { - if len(sig) != len(b.header.LastCommitSignature) { + if len(sig) != len(b.header.LastCommitSignature()) { utils.Logger().Warn(). Int("srcLen", len(sig)). - Int("dstLen", len(b.header.LastCommitSignature)). + Int("dstLen", len(b.header.LastCommitSignature())). Msg("SetLastCommitSig: sig size mismatch") } - copy(b.header.LastCommitSignature[:], sig[:]) - b.header.LastCommitBitmap = append(signers[:0:0], signers...) + var sig2 [96]byte + copy(sig2[:], sig) + b.header.SetLastCommitSignature(sig2) + b.header.SetLastCommitBitmap(signers) } // DeprecatedTd is an old relic for extracting the TD of a block. It is in the @@ -154,26 +156,26 @@ func NewBlock(header *block.Header, txs []*Transaction, receipts []*Receipt, out // TODO: panic if len(txs) != len(receipts) if len(txs) == 0 { - b.header.TxHash = EmptyRootHash + b.header.SetTxHash(EmptyRootHash) } else { - b.header.TxHash = DeriveSha(Transactions(txs)) + b.header.SetTxHash(DeriveSha(Transactions(txs))) b.transactions = make(Transactions, len(txs)) copy(b.transactions, txs) } if len(receipts) == 0 { - b.header.ReceiptHash = EmptyRootHash + b.header.SetReceiptHash(EmptyRootHash) } else { - b.header.ReceiptHash = DeriveSha(Receipts(receipts)) - b.header.Bloom = CreateBloom(receipts) + b.header.SetReceiptHash(DeriveSha(Receipts(receipts))) + b.header.SetBloom(CreateBloom(receipts)) } - b.header.OutgoingReceiptHash = DeriveMultipleShardsSha(CXReceipts(outcxs)) + b.header.SetOutgoingReceiptHash(DeriveMultipleShardsSha(CXReceipts(outcxs))) if len(incxs) == 0 { - b.header.IncomingReceiptHash = EmptyRootHash + b.header.SetIncomingReceiptHash(EmptyRootHash) } else { - b.header.IncomingReceiptHash = DeriveSha(CXReceiptsProofs(incxs)) + b.header.SetIncomingReceiptHash(DeriveSha(CXReceiptsProofs(incxs))) b.incomingReceipts = make(CXReceiptsProofs, len(incxs)) copy(b.incomingReceipts, incxs) } @@ -190,45 +192,14 @@ func NewBlockWithHeader(header *block.Header) *Block { // CopyHeader creates a deep copy of a block header to prevent side effects from // modifying a header variable. +// TODO ek – no longer necessary func CopyHeader(h *block.Header) *block.Header { - // TODO: update with new fields cpy := *h - if cpy.Time = new(big.Int); h.Time != nil { - cpy.Time.Set(h.Time) - } - if cpy.Number = new(big.Int); h.Number != nil { - cpy.Number.Set(h.Number) - } - if cpy.ViewID = new(big.Int); h.ViewID != nil { - cpy.ViewID.Set(h.ViewID) - } - if cpy.Epoch = new(big.Int); h.Epoch != nil { - cpy.Epoch.Set(h.Epoch) - } - if len(h.Extra) > 0 { - cpy.Extra = make([]byte, len(h.Extra)) - copy(cpy.Extra, h.Extra) - } - if len(h.ShardState) > 0 { - cpy.ShardState = make([]byte, len(h.ShardState)) - copy(cpy.ShardState, h.ShardState) - } - if len(h.Vrf) > 0 { - cpy.Vrf = make([]byte, len(h.Vrf)) - copy(cpy.Vrf, h.Vrf) - } - if len(h.Vdf) > 0 { - cpy.Vdf = make([]byte, len(h.Vdf)) - copy(cpy.Vdf, h.Vdf) - } - if len(h.CrossLinks) > 0 { - cpy.CrossLinks = make([]byte, len(h.CrossLinks)) - copy(cpy.CrossLinks, h.CrossLinks) - } - if len(h.LastCommitBitmap) > 0 { - cpy.LastCommitBitmap = make([]byte, len(h.LastCommitBitmap)) - copy(cpy.LastCommitBitmap, h.LastCommitBitmap) - } + // A field value object that lives outside of a header struct is never + // exposed to the outside for external modification, as its getter and + // setter always make a copy. Therefore, we do not have to clone such + // fields, and multiple header structs can safely share the same field value + // objects. return &cpy } @@ -291,52 +262,52 @@ func (b *Block) Transaction(hash common.Hash) *Transaction { } // Number returns header number. -func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) } +func (b *Block) Number() *big.Int { return b.header.Number() } // GasLimit returns header gas limit. -func (b *Block) GasLimit() uint64 { return b.header.GasLimit } +func (b *Block) GasLimit() uint64 { return b.header.GasLimit() } // GasUsed returns header gas used. -func (b *Block) GasUsed() uint64 { return b.header.GasUsed } +func (b *Block) GasUsed() uint64 { return b.header.GasUsed() } // Time is header time. -func (b *Block) Time() *big.Int { return new(big.Int).Set(b.header.Time) } +func (b *Block) Time() *big.Int { return b.header.Time() } // NumberU64 is the header number in uint64. -func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() } +func (b *Block) NumberU64() uint64 { return b.header.Number().Uint64() } // MixDigest is the header mix digest. -func (b *Block) MixDigest() common.Hash { return b.header.MixDigest } +func (b *Block) MixDigest() common.Hash { return b.header.MixDigest() } // ShardID is the header ShardID -func (b *Block) ShardID() uint32 { return b.header.ShardID } +func (b *Block) ShardID() uint32 { return b.header.ShardID() } // Epoch is the header Epoch -func (b *Block) Epoch() *big.Int { return b.header.Epoch } +func (b *Block) Epoch() *big.Int { return b.header.Epoch() } // Bloom returns header bloom. -func (b *Block) Bloom() ethtypes.Bloom { return b.header.Bloom } +func (b *Block) Bloom() ethtypes.Bloom { return b.header.Bloom() } // Coinbase returns header coinbase. -func (b *Block) Coinbase() common.Address { return b.header.Coinbase } +func (b *Block) Coinbase() common.Address { return b.header.Coinbase() } // Root returns header root. -func (b *Block) Root() common.Hash { return b.header.Root } +func (b *Block) Root() common.Hash { return b.header.Root() } // ParentHash return header parent hash. -func (b *Block) ParentHash() common.Hash { return b.header.ParentHash } +func (b *Block) ParentHash() common.Hash { return b.header.ParentHash() } // TxHash returns header tx hash. -func (b *Block) TxHash() common.Hash { return b.header.TxHash } +func (b *Block) TxHash() common.Hash { return b.header.TxHash() } // ReceiptHash returns header receipt hash. -func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash } +func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash() } // OutgoingReceiptHash returns header cross shard receipt hash. -func (b *Block) OutgoingReceiptHash() common.Hash { return b.header.OutgoingReceiptHash } +func (b *Block) OutgoingReceiptHash() common.Hash { return b.header.OutgoingReceiptHash() } // Extra returns header extra. -func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) } +func (b *Block) Extra() []byte { return b.header.Extra() } // Header returns a copy of Header. func (b *Block) Header() *block.Header { return CopyHeader(b.header) } @@ -345,10 +316,10 @@ func (b *Block) Header() *block.Header { return CopyHeader(b.header) } func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles, b.incomingReceipts} } // Vdf returns header Vdf. -func (b *Block) Vdf() []byte { return common.CopyBytes(b.header.Vdf) } +func (b *Block) Vdf() []byte { return b.header.Vdf() } // Vrf returns header Vrf. -func (b *Block) Vrf() []byte { return common.CopyBytes(b.header.Vrf) } +func (b *Block) Vrf() []byte { return b.header.Vrf() } // Size returns the true RLP encoded storage size of the block, either by encoding // and returning it, or returning a previsouly cached value. @@ -451,17 +422,17 @@ func (s blockSorter) Less(i, j int) bool { // Number checks if block b1 is less than block b2. func Number(b1, b2 *Block) bool { - return b1.header.Number.Cmp(b2.header.Number) < 0 + return b1.header.Number().Cmp(b2.header.Number()) < 0 } // AddVrf add vrf into block header func (b *Block) AddVrf(vrf []byte) { - b.header.Vrf = vrf + b.header.SetVrf(vrf) } // AddVdf add vdf into block header func (b *Block) AddVdf(vdf []byte) { - b.header.Vdf = vdf + b.header.SetVdf(vdf) } // AddShardState add shardState into block header @@ -469,12 +440,12 @@ func (b *Block) AddShardState(shardState shard.State) error { // Make a copy because State.Hash() internally sorts entries. // Store the sorted copy. shardState = append(shardState[:0:0], shardState...) - b.header.ShardStateHash = shardState.Hash() + b.header.SetShardStateHash(shardState.Hash()) data, err := rlp.EncodeToBytes(shardState) if err != nil { return err } - b.header.ShardState = data + b.header.SetShardState(data) return nil } diff --git a/core/types/block_test.go b/core/types/block_test.go index 6683664b6..985a6d6ff 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -96,15 +96,16 @@ func TestBlock_SetLastCommitSig(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - b := &Block{header: &block.Header{}} + b := &Block{header: block.NewHeader()} b.SetLastCommitSig(tt.sig, tt.signers) - if !bytes.Equal(tt.sig, b.header.LastCommitSignature[:]) { + sig := b.header.LastCommitSignature() + if !bytes.Equal(tt.sig, sig[:]) { t.Errorf("signature mismatch: expected %+v, actual %+v", - tt.sig, b.header.LastCommitSignature) + tt.sig, sig) } - if !bytes.Equal(tt.signers, b.header.LastCommitBitmap) { + if !bytes.Equal(tt.signers, b.header.LastCommitBitmap()) { t.Errorf("signature mismatch: expected %+v, actual %+v", - tt.signers, b.header.LastCommitBitmap) + tt.signers, b.header.LastCommitBitmap()) } }) } diff --git a/core/types/crosslink.go b/core/types/crosslink.go index a298c3fc9..b6436b2f6 100644 --- a/core/types/crosslink.go +++ b/core/types/crosslink.go @@ -28,12 +28,12 @@ func (cl CrossLink) Header() *block.Header { // ShardID returns shardID func (cl CrossLink) ShardID() uint32 { - return cl.ChainHeader.ShardID + return cl.ChainHeader.ShardID() } // BlockNum returns blockNum func (cl CrossLink) BlockNum() *big.Int { - return cl.ChainHeader.Number + return cl.ChainHeader.Number() } // Hash returns hash @@ -43,12 +43,12 @@ func (cl CrossLink) Hash() common.Hash { // StateRoot returns hash of state root func (cl CrossLink) StateRoot() common.Hash { - return cl.ChainHeader.Root + return cl.ChainHeader.Root() } // OutgoingReceiptsRoot returns hash of cross shard receipts func (cl CrossLink) OutgoingReceiptsRoot() common.Hash { - return cl.ChainHeader.OutgoingReceiptHash + return cl.ChainHeader.OutgoingReceiptHash() } // Serialize returns bytes of cross link rlp-encoded content diff --git a/drand/drand_test.go b/drand/drand_test.go index fd42c8320..be6b94ee1 100644 --- a/drand/drand_test.go +++ b/drand/drand_test.go @@ -128,7 +128,7 @@ func TestVrf(test *testing.T) { tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), 0, big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11}) txs := []*types.Transaction{tx1} - block := types.NewBlock(&block2.Header{Number: big.NewInt(314)}, txs, nil, nil, nil) + block := types.NewBlock(block2.NewHeaderWith().Number(big.NewInt(314)).Header(), txs, nil, nil, nil) blockHash := block.Hash() dRand.vrf(blockHash) diff --git a/hmy/api_backend.go b/hmy/api_backend.go index 0ed8bd52a..eea27177d 100644 --- a/hmy/api_backend.go +++ b/hmy/api_backend.go @@ -67,7 +67,7 @@ func (b *APIBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.Blo if header == nil || err != nil { return nil, nil, err } - stateDb, err := b.hmy.blockchain.StateAt(header.Root) + stateDb, err := b.hmy.blockchain.StateAt(header.Root()) return stateDb, header, err } diff --git a/hmy/bloombits.go b/hmy/bloombits.go index 6e8729517..eae943519 100644 --- a/hmy/bloombits.go +++ b/hmy/bloombits.go @@ -120,7 +120,7 @@ func (b *BloomIndexer) Reset(ctx context.Context, section uint64, lastSectionHea // Process implements core.ChainIndexerBackend, adding a new header's bloom into // the index. func (b *BloomIndexer) Process(ctx context.Context, header *block.Header) error { - b.gen.AddBloom(uint(header.Number.Uint64()-b.section*b.size), header.Bloom) + b.gen.AddBloom(uint(header.Number().Uint64()-b.section*b.size), header.Bloom()) b.head = header.Hash() return nil } diff --git a/hmyclient/hmyclient.go b/hmyclient/hmyclient.go index 58a8ad87e..ec868fea6 100644 --- a/hmyclient/hmyclient.go +++ b/hmyclient/hmyclient.go @@ -107,10 +107,10 @@ func (c *Client) getBlock(ctx context.Context, method string, args ...interface{ return nil, err } // Quick-verify transaction. This mostly helps with debugging the server. - if head.TxHash == types.EmptyRootHash && len(body.Transactions) > 0 { + if head.TxHash() == types.EmptyRootHash && len(body.Transactions) > 0 { return nil, fmt.Errorf("server returned non-empty transaction list but block header indicates no transactions") } - if head.TxHash != types.EmptyRootHash && len(body.Transactions) == 0 { + if head.TxHash() != types.EmptyRootHash && len(body.Transactions) == 0 { return nil, fmt.Errorf("server returned empty transaction list but block header indicates transactions") } // Fill the sender cache of transactions in the block. diff --git a/internal/chain/engine.go b/internal/chain/engine.go index 83ccae17e..97e529d18 100644 --- a/internal/chain/engine.go +++ b/internal/chain/engine.go @@ -27,17 +27,17 @@ func (e *engineImpl) SealHash(header *block.Header) (hash common.Hash) { hasher := sha3.NewLegacyKeccak256() // TODO: update with new fields if err := rlp.Encode(hasher, []interface{}{ - header.ParentHash, - header.Coinbase, - header.Root, - header.TxHash, - header.ReceiptHash, - header.Bloom, - header.Number, - header.GasLimit, - header.GasUsed, - header.Time, - header.Extra, + header.ParentHash(), + header.Coinbase(), + header.Root(), + header.TxHash(), + header.ReceiptHash(), + header.Bloom(), + header.Number(), + header.GasLimit(), + header.GasUsed(), + header.Time(), + header.Extra(), }); err != nil { utils.Logger().Warn().Err(err).Msg("rlp.Encode failed") } @@ -66,7 +66,7 @@ func (e *engineImpl) Prepare(chain engine.ChainReader, header *block.Header) err // VerifyHeader checks whether a header conforms to the consensus rules of the bft engine. func (e *engineImpl) VerifyHeader(chain engine.ChainReader, header *block.Header, seal bool) error { - parentHeader := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) + parentHeader := chain.GetHeader(header.ParentHash(), header.Number().Uint64()-1) if parentHeader == nil { return engine.ErrUnknownAncestor } @@ -91,22 +91,22 @@ func (e *engineImpl) VerifyHeaders(chain engine.ChainReader, headers []*block.He // retrievePublicKeysFromLastBlock finds the public keys of last block's committee func retrievePublicKeysFromLastBlock(bc engine.ChainReader, header *block.Header) ([]*bls.PublicKey, error) { - parentHeader := bc.GetHeaderByHash(header.ParentHash) + parentHeader := bc.GetHeaderByHash(header.ParentHash()) if parentHeader == nil { return nil, ctxerror.New("cannot find parent block header in DB", - "parentHash", header.ParentHash) + "parentHash", header.ParentHash()) } - parentShardState, err := bc.ReadShardState(parentHeader.Epoch) + parentShardState, err := bc.ReadShardState(parentHeader.Epoch()) if err != nil { return nil, ctxerror.New("cannot read shard state", - "epoch", parentHeader.Epoch, + "epoch", parentHeader.Epoch(), ).WithCause(err) } - parentCommittee := parentShardState.FindCommitteeByID(parentHeader.ShardID) + parentCommittee := parentShardState.FindCommitteeByID(parentHeader.ShardID()) if parentCommittee == nil { return nil, ctxerror.New("cannot find shard in the shard state", - "parentBlockNumber", parentHeader.Number, - "shardID", parentHeader.ShardID, + "parentBlockNumber", parentHeader.Number(), + "shardID", parentHeader.ShardID(), ) } var committerKeys []*bls.PublicKey @@ -125,23 +125,25 @@ func retrievePublicKeysFromLastBlock(bc engine.ChainReader, header *block.Header // VerifySeal implements Engine, checking whether the given block satisfies // the PoS difficulty requirements, i.e. >= 2f+1 valid signatures from the committee func (e *engineImpl) VerifySeal(chain engine.ChainReader, header *block.Header) error { - if chain.CurrentHeader().Number.Uint64() <= uint64(1) { + if chain.CurrentHeader().Number().Uint64() <= uint64(1) { return nil } publicKeys, err := retrievePublicKeysFromLastBlock(chain, header) if err != nil { return ctxerror.New("[VerifySeal] Cannot retrieve publickeys from last block").WithCause(err) } - payload := append(header.LastCommitSignature[:], header.LastCommitBitmap...) + sig := header.LastCommitSignature() + payload := append(sig[:], header.LastCommitBitmap()...) aggSig, mask, err := ReadSignatureBitmapByPublicKeys(payload, publicKeys) if err != nil { return ctxerror.New("[VerifySeal] Unable to deserialize the LastCommitSignature and LastCommitBitmap in Block Header").WithCause(err) } - parentHeader := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) + parentHash := header.ParentHash() + parentHeader := chain.GetHeader(parentHash, header.Number().Uint64()-1) parentQuorum, err := QuorumForBlock(chain, parentHeader) if err != nil { return errors.Wrapf(err, - "cannot calculate quorum for block %s", header.Number) + "cannot calculate quorum for block %s", header.Number()) } if count := utils.CountOneBits(mask.Bitmap); count < parentQuorum { return ctxerror.New("[VerifySeal] Not enough signature in LastCommitSignature from Block Header", @@ -149,11 +151,11 @@ func (e *engineImpl) VerifySeal(chain engine.ChainReader, header *block.Header) } blockNumHash := make([]byte, 8) - binary.LittleEndian.PutUint64(blockNumHash, header.Number.Uint64()-1) - lastCommitPayload := append(blockNumHash, header.ParentHash[:]...) + binary.LittleEndian.PutUint64(blockNumHash, header.Number().Uint64()-1) + lastCommitPayload := append(blockNumHash, parentHash[:]...) if !aggSig.VerifyHash(mask.AggregatePublic, lastCommitPayload) { - return ctxerror.New("[VerifySeal] Unable to verify aggregated signature from last block", "lastBlockNum", header.Number.Uint64()-1, "lastBlockHash", header.ParentHash) + return ctxerror.New("[VerifySeal] Unable to verify aggregated signature from last block", "lastBlockNum", header.Number().Uint64()-1, "lastBlockHash", parentHash) } return nil } @@ -166,7 +168,7 @@ func (e *engineImpl) Finalize(chain engine.ChainReader, header *block.Header, st if err := AccumulateRewards(chain, state, header); err != nil { return nil, ctxerror.New("cannot pay block reward").WithCause(err) } - header.Root = state.IntermediateRoot(chain.Config().IsS3(header.Epoch)) + header.SetRoot(state.IntermediateRoot(chain.Config().IsS3(header.Epoch()))) return types.NewBlock(header, txs, receipts, outcxs, incxs), nil } @@ -174,15 +176,15 @@ func (e *engineImpl) Finalize(chain engine.ChainReader, header *block.Header, st func QuorumForBlock( chain engine.ChainReader, h *block.Header, ) (quorum int, err error) { - ss, err := chain.ReadShardState(h.Epoch) + ss, err := chain.ReadShardState(h.Epoch()) if err != nil { return 0, errors.Wrapf(err, - "cannot read shard state for epoch %s", h.Epoch) + "cannot read shard state for epoch %s", h.Epoch()) } - c := ss.FindCommitteeByID(h.ShardID) + c := ss.FindCommitteeByID(h.ShardID()) if c == nil { return 0, errors.Errorf( - "cannot find shard %d in shard state", h.ShardID) + "cannot find shard %d in shard state", h.ShardID()) } return (len(c.NodeList))*2/3 + 1, nil } diff --git a/internal/chain/reward.go b/internal/chain/reward.go index d21179f75..28b1ebc76 100644 --- a/internal/chain/reward.go +++ b/internal/chain/reward.go @@ -25,7 +25,7 @@ var BlockReward = new(big.Int).Mul(big.NewInt(24), big.NewInt(denominations.One) func AccumulateRewards( bc engine.ChainReader, state *state.DB, header *block.Header, ) error { - blockNum := header.Number.Uint64() + blockNum := header.Number().Uint64() if blockNum == 0 { // Epoch block has no parent to reward. return nil @@ -33,27 +33,27 @@ func AccumulateRewards( // TODO ek – retrieving by parent number (blockNum - 1) doesn't work, // while it is okay with hash. Sounds like DB inconsistency. // Figure out why. - parentHeader := bc.GetHeaderByHash(header.ParentHash) + parentHeader := bc.GetHeaderByHash(header.ParentHash()) if parentHeader == nil { return ctxerror.New("cannot find parent block header in DB", - "parentHash", header.ParentHash) + "parentHash", header.ParentHash()) } - if parentHeader.Number.Cmp(common.Big0) == 0 { + if parentHeader.Number().Cmp(common.Big0) == 0 { // Parent is an epoch block, // which is not signed in the usual manner therefore rewards nothing. return nil } - parentShardState, err := bc.ReadShardState(parentHeader.Epoch) + parentShardState, err := bc.ReadShardState(parentHeader.Epoch()) if err != nil { return ctxerror.New("cannot read shard state", - "epoch", parentHeader.Epoch, + "epoch", parentHeader.Epoch(), ).WithCause(err) } - parentCommittee := parentShardState.FindCommitteeByID(parentHeader.ShardID) + parentCommittee := parentShardState.FindCommitteeByID(parentHeader.ShardID()) if parentCommittee == nil { return ctxerror.New("cannot find shard in the shard state", - "parentBlockNumber", parentHeader.Number, - "shardID", parentHeader.ShardID, + "parentBlockNumber", parentHeader.Number(), + "shardID", parentHeader.ShardID(), ) } var committerKeys []*bls.PublicKey @@ -70,7 +70,7 @@ func AccumulateRewards( if err != nil { return ctxerror.New("cannot create group sig mask").WithCause(err) } - if err := mask.SetMask(header.LastCommitBitmap); err != nil { + if err := mask.SetMask(header.LastCommitBitmap()); err != nil { return ctxerror.New("cannot set group sig mask bits").WithCause(err) } totalAmount := big.NewInt(0) diff --git a/internal/hmyapi/blockchain.go b/internal/hmyapi/blockchain.go index 2db672853..e79fba2c0 100644 --- a/internal/hmyapi/blockchain.go +++ b/internal/hmyapi/blockchain.go @@ -99,7 +99,7 @@ func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address string, bl // BlockNumber returns the block number of the chain head. func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 { header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available - return hexutil.Uint64(header.Number.Uint64()) + return hexutil.Uint64(header.Number().Uint64()) } // Call executes the given transaction on the state for the given block number. diff --git a/internal/hmyapi/filters/filter.go b/internal/hmyapi/filters/filter.go index 2fd577607..e5dbf0e41 100644 --- a/internal/hmyapi/filters/filter.go +++ b/internal/hmyapi/filters/filter.go @@ -137,7 +137,7 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { if header == nil { return nil, nil } - head := header.Number.Uint64() + head := header.Number().Uint64() if f.begin == -1 { f.begin = int64(head) @@ -235,7 +235,7 @@ func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, e // blockLogs returns the logs matching the filter criteria within a single block. func (f *Filter) blockLogs(ctx context.Context, header *block.Header) (logs []*types.Log, err error) { - if bloomFilter(header.Bloom, f.addresses, f.topics) { + if bloomFilter(header.Bloom(), f.addresses, f.topics) { found, err := f.checkMatches(ctx, header) if err != nil { return logs, err diff --git a/internal/hmyapi/filters/filter_system.go b/internal/hmyapi/filters/filter_system.go index fc74fd9ea..ab66dcd06 100644 --- a/internal/hmyapi/filters/filter_system.go +++ b/internal/hmyapi/filters/filter_system.go @@ -378,13 +378,13 @@ func (es *EventSystem) lightFilterNewHead(newHeader *block.Header, callBack func // find common ancestor, create list of rolled back and new block hashes var oldHeaders, newHeaders []*block.Header for oldh.Hash() != newh.Hash() { - if oldh.Number.Uint64() >= newh.Number.Uint64() { + if oldh.Number().Uint64() >= newh.Number().Uint64() { oldHeaders = append(oldHeaders, oldh) - oldh = rawdb.ReadHeader(es.backend.ChainDb(), oldh.ParentHash, oldh.Number.Uint64()-1) + oldh = rawdb.ReadHeader(es.backend.ChainDb(), oldh.ParentHash(), oldh.Number().Uint64()-1) } - if oldh.Number.Uint64() < newh.Number.Uint64() { + if oldh.Number().Uint64() < newh.Number().Uint64() { newHeaders = append(newHeaders, newh) - newh = rawdb.ReadHeader(es.backend.ChainDb(), newh.ParentHash, newh.Number.Uint64()-1) + newh = rawdb.ReadHeader(es.backend.ChainDb(), newh.ParentHash(), newh.Number().Uint64()-1) if newh == nil { // happens when CHT syncing, nothing to do newh = oldh @@ -403,7 +403,7 @@ func (es *EventSystem) lightFilterNewHead(newHeader *block.Header, callBack func // filter logs of a single header in light client mode func (es *EventSystem) lightFilterLogs(header *block.Header, addresses []common.Address, topics [][]common.Hash, remove bool) []*types.Log { - if bloomFilter(header.Bloom, addresses, topics) { + if bloomFilter(header.Bloom(), addresses, topics) { // Get the logs of the block ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() diff --git a/internal/hmyapi/types.go b/internal/hmyapi/types.go index 73009cbbb..4ceff684e 100644 --- a/internal/hmyapi/types.go +++ b/internal/hmyapi/types.go @@ -92,22 +92,22 @@ type RPCBlock struct { func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { head := b.Header() // copies the header once fields := map[string]interface{}{ - "number": (*hexutil.Big)(head.Number), + "number": (*hexutil.Big)(head.Number()), "hash": b.Hash(), - "parentHash": head.ParentHash, + "parentHash": head.ParentHash(), "nonce": 0, // Remove this because we don't have it in our header - "mixHash": head.MixDigest, - "logsBloom": head.Bloom, - "stateRoot": head.Root, - "miner": head.Coinbase, + "mixHash": head.MixDigest(), + "logsBloom": head.Bloom(), + "stateRoot": head.Root(), + "miner": head.Coinbase(), "difficulty": 0, // Remove this because we don't have it in our header - "extraData": hexutil.Bytes(head.Extra), + "extraData": hexutil.Bytes(head.Extra()), "size": hexutil.Uint64(b.Size()), - "gasLimit": hexutil.Uint64(head.GasLimit), - "gasUsed": hexutil.Uint64(head.GasUsed), - "timestamp": hexutil.Uint64(head.Time.Uint64()), - "transactionsRoot": head.TxHash, - "receiptsRoot": head.ReceiptHash, + "gasLimit": hexutil.Uint64(head.GasLimit()), + "gasUsed": hexutil.Uint64(head.GasUsed()), + "timestamp": hexutil.Uint64(head.Time().Uint64()), + "transactionsRoot": head.TxHash(), + "receiptsRoot": head.ReceiptHash(), } if inclTx { diff --git a/node/node.go b/node/node.go index c79b8a32c..a246653e2 100644 --- a/node/node.go +++ b/node/node.go @@ -339,7 +339,7 @@ func (node *Node) StartServer() { // Currently used for stats reporting purpose func (node *Node) countNumTransactionsInBlockchain() int { count := 0 - for block := node.Blockchain().CurrentBlock(); block != nil; block = node.Blockchain().GetBlockByHash(block.Header().ParentHash) { + for block := node.Blockchain().CurrentBlock(); block != nil; block = node.Blockchain().GetBlockByHash(block.Header().ParentHash()) { count += len(block.Transactions()) } return count diff --git a/node/node_cross_shard.go b/node/node_cross_shard.go index ffa23f32e..156fad956 100644 --- a/node/node_cross_shard.go +++ b/node/node_cross_shard.go @@ -38,9 +38,9 @@ func (node *Node) ProcessHeaderMessage(msgPayload []byte) { firstCrossLinkBlock := core.EpochFirstBlock(node.Blockchain().Config().CrossLinkEpoch) for _, header := range headers { - if header.Number.Cmp(firstCrossLinkBlock) >= 0 { + if header.Number().Cmp(firstCrossLinkBlock) >= 0 { // Only process cross link starting from FirstCrossLinkBlock - utils.Logger().Debug().Msgf("[ProcessHeaderMessage] Add Pending CrossLink, shardID %d, blockNum %d", header.ShardID, header.Number) + utils.Logger().Debug().Msgf("[ProcessHeaderMessage] Add Pending CrossLink, shardID %d, blockNum %d", header.ShardID(), header.Number()) crossLinkHeadersToProcess = append(crossLinkHeadersToProcess, header) } } @@ -53,22 +53,22 @@ func (node *Node) ProcessHeaderMessage(msgPayload []byte) { if len(headersToQuque) > crossLinkBatchSize { break } - exist, err := node.Blockchain().ReadCrossLink(header.ShardID, header.Number.Uint64(), false) + exist, err := node.Blockchain().ReadCrossLink(header.ShardID(), header.Number().Uint64(), false) if err == nil && exist != nil { utils.Logger().Debug(). - Msgf("[ProcessingHeader] Cross Link already exists, pass. Block num: %d, shardID %d", header.Number, header.ShardID) + Msgf("[ProcessingHeader] Cross Link already exists, pass. Block num: %d, shardID %d", header.Number(), header.ShardID()) continue } - if header.Number.Cmp(firstCrossLinkBlock) > 0 { // Directly trust the first cross-link + if header.Number().Cmp(firstCrossLinkBlock) > 0 { // Directly trust the first cross-link // Sanity check on the previous link with the new link - previousLink, err := node.Blockchain().ReadCrossLink(header.ShardID, header.Number.Uint64()-1, false) + previousLink, err := node.Blockchain().ReadCrossLink(header.ShardID(), header.Number().Uint64()-1, false) if err != nil { - previousLink, err = node.Blockchain().ReadCrossLink(header.ShardID, header.Number.Uint64()-1, true) + previousLink, err = node.Blockchain().ReadCrossLink(header.ShardID(), header.Number().Uint64()-1, true) if err != nil { headersToQuque = append(headersToQuque, header) utils.Logger().Error().Err(err). - Msgf("[ProcessingHeader] ReadCrossLink cannot read previousLink with number %d, shardID %d", header.Number.Uint64()-1, header.ShardID) + Msgf("[ProcessingHeader] ReadCrossLink cannot read previousLink with number %d, shardID %d", header.Number().Uint64()-1, header.ShardID()) continue } } @@ -77,14 +77,14 @@ func (node *Node) ProcessHeaderMessage(msgPayload []byte) { if err != nil { utils.Logger().Error(). Err(err). - Msgf("[ProcessingHeader] Failed to verify new cross link header for shardID %d, blockNum %d", header.ShardID, header.Number) + Msgf("[ProcessingHeader] Failed to verify new cross link header for shardID %d, blockNum %d", header.ShardID(), header.Number()) continue } } crossLink := types.NewCrossLink(header) utils.Logger().Debug(). - Msgf("[ProcessingHeader] committing for shardID %d, blockNum %d", header.ShardID, header.Number.Uint64()) + Msgf("[ProcessingHeader] committing for shardID %d, blockNum %d", header.ShardID(), header.Number().Uint64()) node.Blockchain().WriteCrossLinks(types.CrossLinks{crossLink}, true) } @@ -121,7 +121,7 @@ func (node *Node) verifyIncomingReceipts(block *types.Block) error { if len(cxps) > 0 { incomingReceiptHash = types.DeriveSha(cxps) } - if incomingReceiptHash != block.Header().IncomingReceiptHash { + if incomingReceiptHash != block.Header().IncomingReceiptHash() { return ctxerror.New("[verifyIncomingReceipts] Invalid IncomingReceiptHash in block header") } @@ -147,7 +147,7 @@ func (node *Node) compareCrosslinkWithReceipts(cxp *types.CXReceiptsProof) error return ctxerror.New("[compareCrosslinkWithReceipts] Cannot get crosslink", "blockNum", blockNum, "shardID", shardID).WithCause(err) } hash = crossLink.ChainHeader.Hash() - outgoingReceiptHash = crossLink.ChainHeader.OutgoingReceiptHash + outgoingReceiptHash = crossLink.ChainHeader.OutgoingReceiptHash() } // verify the source block hash is from a finalized block if hash == cxp.MerkleProof.BlockHash && outgoingReceiptHash == cxp.MerkleProof.CXReceiptHash { @@ -160,16 +160,17 @@ func (node *Node) compareCrosslinkWithReceipts(cxp *types.CXReceiptsProof) error func (node *Node) VerifyCrosslinkHeader(prevHeader, header *block.Header) error { // TODO: add fork choice rule - if prevHeader.Hash() != header.ParentHash { - return ctxerror.New("[CrossLink] Invalid cross link header - parent hash mismatch", "shardID", header.ShardID, "blockNum", header.Number) + parentHash := header.ParentHash() + if prevHeader.Hash() != parentHash { + return ctxerror.New("[CrossLink] Invalid cross link header - parent hash mismatch", "shardID", header.ShardID(), "blockNum", header.Number()) } // Verify signature of the new cross link header - shardState, err := node.Blockchain().ReadShardState(prevHeader.Epoch) - committee := shardState.FindCommitteeByID(prevHeader.ShardID) + shardState, err := node.Blockchain().ReadShardState(prevHeader.Epoch()) + committee := shardState.FindCommitteeByID(prevHeader.ShardID()) if err != nil || committee == nil { - return ctxerror.New("[CrossLink] Failed to read shard state for cross link header", "shardID", header.ShardID, "blockNum", header.Number).WithCause(err) + return ctxerror.New("[CrossLink] Failed to read shard state for cross link header", "shardID", header.ShardID(), "blockNum", header.Number()).WithCause(err) } var committerKeys []*bls.PublicKey @@ -184,29 +185,30 @@ func (node *Node) VerifyCrosslinkHeader(prevHeader, header *block.Header) error committerKeys = append(committerKeys, committerKey) } if !parseKeysSuccess { - return ctxerror.New("[CrossLink] cannot convert BLS public key", "shardID", header.ShardID, "blockNum", header.Number).WithCause(err) + return ctxerror.New("[CrossLink] cannot convert BLS public key", "shardID", header.ShardID(), "blockNum", header.Number()).WithCause(err) } - if header.Number.Uint64() > 1 { // First block doesn't have last sig + if header.Number().Uint64() > 1 { // First block doesn't have last sig mask, err := bls_cosi.NewMask(committerKeys, nil) if err != nil { - return ctxerror.New("cannot create group sig mask", "shardID", header.ShardID, "blockNum", header.Number).WithCause(err) + return ctxerror.New("cannot create group sig mask", "shardID", header.ShardID(), "blockNum", header.Number()).WithCause(err) } - if err := mask.SetMask(header.LastCommitBitmap); err != nil { - return ctxerror.New("cannot set group sig mask bits", "shardID", header.ShardID, "blockNum", header.Number).WithCause(err) + if err := mask.SetMask(header.LastCommitBitmap()); err != nil { + return ctxerror.New("cannot set group sig mask bits", "shardID", header.ShardID(), "blockNum", header.Number()).WithCause(err) } aggSig := bls.Sign{} - err = aggSig.Deserialize(header.LastCommitSignature[:]) + sig := header.LastCommitSignature() + err = aggSig.Deserialize(sig[:]) if err != nil { return ctxerror.New("unable to deserialize multi-signature from payload").WithCause(err) } blockNumBytes := make([]byte, 8) - binary.LittleEndian.PutUint64(blockNumBytes, header.Number.Uint64()-1) - commitPayload := append(blockNumBytes, header.ParentHash[:]...) + binary.LittleEndian.PutUint64(blockNumBytes, header.Number().Uint64()-1) + commitPayload := append(blockNumBytes, parentHash[:]...) if !aggSig.VerifyHash(mask.AggregatePublic, commitPayload) { - return ctxerror.New("Failed to verify the signature for cross link header ", "shardID", header.ShardID, "blockNum", header.Number) + return ctxerror.New("Failed to verify the signature for cross link header ", "shardID", header.ShardID(), "blockNum", header.Number()) } } return nil @@ -218,7 +220,7 @@ func (node *Node) ProposeCrossLinkDataForBeaconchain() (types.CrossLinks, error) Uint64("blockNum", node.Blockchain().CurrentBlock().NumberU64()+1). Msg("Proposing cross links ...") curBlock := node.Blockchain().CurrentBlock() - numShards := core.ShardingSchedule.InstanceForEpoch(curBlock.Header().Epoch).NumShards() + numShards := core.ShardingSchedule.InstanceForEpoch(curBlock.Header().Epoch()).NumShards() shardCrossLinks := make([]types.CrossLinks, numShards) diff --git a/node/node_handler.go b/node/node_handler.go index 6f50cc22b..8384d3ea9 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -297,7 +297,7 @@ func (node *Node) BroadcastCrossLinkHeader(newBlock *types.Block) { utils.Logger().Info().Msgf("[BroadcastCrossLinkHeader] Broadcasting Block Headers, latestBlockNum %d, currentBlockNum %d, Number of Headers %d", latestBlockNum, newBlock.NumberU64(), len(headers)) for _, header := range headers { - utils.Logger().Debug().Msgf("[BroadcastCrossLinkHeader] Broadcasting %d", header.Number.Uint64()) + utils.Logger().Debug().Msgf("[BroadcastCrossLinkHeader] Broadcasting %d", header.Number().Uint64()) } node.host.SendMessageToGroups([]p2p.GroupID{node.NodeConfig.GetBeaconGroupID()}, host.ConstructP2pMessage(byte(0), proto_node.ConstructCrossLinkHeadersMessage(headers))) } @@ -305,7 +305,7 @@ func (node *Node) BroadcastCrossLinkHeader(newBlock *types.Block) { // BroadcastCXReceipts broadcasts cross shard receipts to correspoding // destination shards func (node *Node) BroadcastCXReceipts(newBlock *types.Block) { - epoch := newBlock.Header().Epoch + epoch := newBlock.Header().Epoch() shardingConfig := core.ShardingSchedule.InstanceForEpoch(epoch) shardNum := int(shardingConfig.NumShards()) myShardID := node.Consensus.ShardID @@ -386,22 +386,22 @@ func (node *Node) VerifyNewBlock(newBlock *types.Block) error { // VerifyBlockCrossLinks verifies the cross links of the block func (node *Node) VerifyBlockCrossLinks(block *types.Block) error { - if len(block.Header().CrossLinks) == 0 { + if len(block.Header().CrossLinks()) == 0 { return nil } crossLinks := &types.CrossLinks{} - err := rlp.DecodeBytes(block.Header().CrossLinks, crossLinks) + err := rlp.DecodeBytes(block.Header().CrossLinks(), crossLinks) if err != nil { return ctxerror.New("[CrossLinkVerification] failed to decode cross links", "blockHash", block.Hash(), - "crossLinks", len(block.Header().CrossLinks), + "crossLinks", len(block.Header().CrossLinks()), ).WithCause(err) } if !crossLinks.IsSorted() { return ctxerror.New("[CrossLinkVerification] cross links are not sorted", "blockHash", block.Hash(), - "crossLinks", len(block.Header().CrossLinks), + "crossLinks", len(block.Header().CrossLinks()), ) } @@ -420,7 +420,7 @@ func (node *Node) VerifyBlockCrossLinks(block *types.Block) error { } } } else { - if (*crossLinks)[i-1].Header().ShardID != crossLink.Header().ShardID { + if (*crossLinks)[i-1].Header().ShardID() != crossLink.Header().ShardID() { if crossLink.BlockNum().Cmp(firstCrossLinkBlock) > 0 { lastLink, err = node.Blockchain().ReadShardLastCrossLink(crossLink.ShardID()) if err != nil { @@ -457,7 +457,7 @@ var BigMaxUint64 = new(big.Int).SetBytes([]byte{ func (node *Node) validateNewShardState(block *types.Block, stakeInfo *map[common.Address]*structs.StakeInfo) error { // Common case first – blocks without resharding proposal header := block.Header() - if header.ShardStateHash == (common.Hash{}) { + if header.ShardStateHash() == (common.Hash{}) { // No new shard state was proposed if block.ShardID() == 0 { if core.IsEpochLastBlock(block) { @@ -475,7 +475,7 @@ func (node *Node) validateNewShardState(block *types.Block, stakeInfo *map[commo return nil } shardState := &shard.State{} - err := rlp.DecodeBytes(header.ShardState, shardState) + err := rlp.DecodeBytes(header.ShardState(), shardState) if err != nil { return err } @@ -483,7 +483,7 @@ func (node *Node) validateNewShardState(block *types.Block, stakeInfo *map[commo if block.ShardID() == 0 { // Beacon validators independently recalculate the master state and // compare it against the proposed copy. - nextEpoch := new(big.Int).Add(block.Header().Epoch, common.Big1) + nextEpoch := new(big.Int).Add(block.Header().Epoch(), common.Big1) // TODO ek – this may be called from regular shards, // for vetting beacon chain blocks received during block syncing. // DRand may or or may not get in the way. Test this out. @@ -650,7 +650,7 @@ func (node *Node) broadcastEpochShardState(newBlock *types.Block) error { } epochShardStateMessage := proto_node.ConstructEpochShardStateMessage( shard.EpochShardState{ - Epoch: newBlock.Header().Epoch.Uint64() + 1, + Epoch: newBlock.Header().Epoch().Uint64() + 1, ShardState: shardState, }, ) @@ -666,7 +666,7 @@ func (node *Node) AddNewBlock(newBlock *types.Block) error { utils.Logger().Error(). Err(err). Uint64("blockNum", newBlock.NumberU64()). - Bytes("parentHash", newBlock.Header().ParentHash.Bytes()[:]). + Bytes("parentHash", newBlock.Header().ParentHash().Bytes()[:]). Bytes("hash", newBlock.Header().Hash().Bytes()[:]). Msg("Error Adding new block to blockchain") } else { diff --git a/node/node_newblock.go b/node/node_newblock.go index 44e5ab77f..56a9afb28 100644 --- a/node/node_newblock.go +++ b/node/node_newblock.go @@ -130,7 +130,8 @@ func (node *Node) proposeShardStateWithoutBeaconSync(block *types.Block) shard.S if block == nil || !core.IsEpochLastBlock(block) { return nil } - nextEpoch := new(big.Int).Add(block.Header().Epoch, common.Big1) + + nextEpoch := new(big.Int).Add(block.Header().Epoch(), common.Big1) return core.GetShardState(nextEpoch) } @@ -150,7 +151,7 @@ func (node *Node) proposeBeaconShardState(block *types.Block) error { // We haven't reached the end of this epoch; don't propose yet. return nil } - nextEpoch := new(big.Int).Add(block.Header().Epoch, common.Big1) + nextEpoch := new(big.Int).Add(block.Header().Epoch(), common.Big1) shardState, err := core.CalculateNewShardState( node.Blockchain(), nextEpoch, &node.CurrentStakes) if err != nil { diff --git a/node/worker/worker.go b/node/worker/worker.go index 32ff3d6ea..40d183fa7 100644 --- a/node/worker/worker.go +++ b/node/worker/worker.go @@ -99,7 +99,7 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra } if w.current.gasPool == nil { - w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) + w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit()) } selected := types.Transactions{} @@ -143,7 +143,7 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra utils.Logger().Info().Str("txId", tx.Hash().Hex()).Uint64("txGasLimit", tx.Gas()).Msg("Transaction gas limit info") } - utils.Logger().Info().Uint64("newBlockNum", newBlockNum).Uint64("blockGasLimit", w.current.header.GasLimit).Uint64("blockGasUsed", w.current.header.GasUsed).Msg("Block gas limit and usage info") + utils.Logger().Info().Uint64("newBlockNum", newBlockNum).Uint64("blockGasLimit", w.current.header.GasLimit()).Uint64("blockGasUsed", w.current.header.GasUsed()).Msg("Block gas limit and usage info") return selected, unselected, invalid } @@ -151,7 +151,9 @@ func (w *Worker) SelectTransactionsForNewBlock(newBlockNum uint64, txs types.Tra func (w *Worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { snap := w.current.state.Snapshot() - receipt, cx, _, err := core.ApplyTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, vm.Config{}) + gasUsed := w.current.header.GasUsed() + receipt, cx, _, err := core.ApplyTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &gasUsed, vm.Config{}) + w.current.header.SetGasUsed(gasUsed) if err != nil { w.current.state.RevertToSnapshot(snap) return nil, err @@ -180,7 +182,7 @@ func (w *Worker) CommitTransactions(txs types.Transactions, coinbase common.Addr } if w.current.gasPool == nil { - w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) + w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit()) } for _, tx := range txs { snap := w.current.state.Snapshot() @@ -197,13 +199,13 @@ func (w *Worker) CommitTransactions(txs types.Transactions, coinbase common.Addr // CommitReceipts commits a list of already verified incoming cross shard receipts func (w *Worker) CommitReceipts(receiptsList []*types.CXReceiptsProof) error { if w.current.gasPool == nil { - w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) + w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit()) } if len(receiptsList) == 0 { - w.current.header.IncomingReceiptHash = types.EmptyRootHash + w.current.header.SetIncomingReceiptHash(types.EmptyRootHash) } else { - w.current.header.IncomingReceiptHash = types.DeriveSha(types.CXReceiptsProofs(receiptsList)) + w.current.header.SetIncomingReceiptHash(types.DeriveSha(types.CXReceiptsProofs(receiptsList))) } for _, cx := range receiptsList { @@ -225,22 +227,22 @@ func (w *Worker) UpdateCurrent(coinbase common.Address) error { num := parent.Number() timestamp := time.Now().Unix() // New block's epoch is the same as parent's... - epoch := new(big.Int).Set(parent.Header().Epoch) + epoch := new(big.Int).Set(parent.Header().Epoch()) // TODO: Don't depend on sharding state for epoch change. - if len(parent.Header().ShardState) > 0 && parent.NumberU64() != 0 { + if len(parent.Header().ShardState()) > 0 && parent.NumberU64() != 0 { // ... except if parent has a resharding assignment it increases by 1. epoch = epoch.Add(epoch, common.Big1) } - header := &block.Header{ - ParentHash: parent.Hash(), - Number: num.Add(num, common.Big1), - GasLimit: core.CalcGasLimit(parent, w.gasFloor, w.gasCeil), - Time: big.NewInt(timestamp), - Epoch: epoch, - ShardID: w.chain.ShardID(), - Coinbase: coinbase, - } + header := block.NewHeaderWith(). + ParentHash(parent.Hash()). + Number(num.Add(num, common.Big1)). + GasLimit(core.CalcGasLimit(parent, w.gasFloor, w.gasCeil)). + Time(big.NewInt(timestamp)). + Epoch(epoch). + ShardID(w.chain.ShardID()). + Coinbase(coinbase). + Header() return w.makeCurrent(parent, header) } @@ -281,32 +283,33 @@ func (w *Worker) IncomingReceipts() []*types.CXReceiptsProof { // ProposeShardStateWithoutBeaconSync proposes the next shard state for next epoch. func (w *Worker) ProposeShardStateWithoutBeaconSync() shard.State { - if !core.ShardingSchedule.IsLastBlock(w.current.header.Number.Uint64()) { + if !core.ShardingSchedule.IsLastBlock(w.current.header.Number().Uint64()) { return nil } - nextEpoch := new(big.Int).Add(w.current.header.Epoch, common.Big1) + nextEpoch := new(big.Int).Add(w.current.header.Epoch(), common.Big1) return core.GetShardState(nextEpoch) } // FinalizeNewBlock generate a new block for the next consensus round. func (w *Worker) FinalizeNewBlock(sig []byte, signers []byte, viewID uint64, coinbase common.Address, crossLinks types.CrossLinks, shardState shard.State) (*types.Block, error) { if len(sig) > 0 && len(signers) > 0 { - copy(w.current.header.LastCommitSignature[:], sig[:]) - w.current.header.LastCommitBitmap = append(signers[:0:0], signers...) + sig2 := w.current.header.LastCommitSignature() + copy(sig2[:], sig[:]) + w.current.header.SetLastCommitSignature(sig2) + w.current.header.SetLastCommitBitmap(signers) } - w.current.header.Coinbase = coinbase - w.current.header.ViewID = new(big.Int) - w.current.header.ViewID.SetUint64(viewID) + w.current.header.SetCoinbase(coinbase) + w.current.header.SetViewID(new(big.Int).SetUint64(viewID)) // Cross Links if crossLinks != nil && len(crossLinks) != 0 { crossLinkData, err := rlp.EncodeToBytes(crossLinks) if err == nil { utils.Logger().Debug(). - Uint64("blockNum", w.current.header.Number.Uint64()). + Uint64("blockNum", w.current.header.Number().Uint64()). Int("numCrossLinks", len(crossLinks)). Msg("Successfully proposed cross links into new block") - w.current.header.CrossLinks = crossLinkData + w.current.header.SetCrossLinks(crossLinkData) } else { utils.Logger().Debug().Err(err).Msg("Failed to encode proposed cross links") return nil, err @@ -315,10 +318,10 @@ func (w *Worker) FinalizeNewBlock(sig []byte, signers []byte, viewID uint64, coi // Shard State if shardState != nil && len(shardState) != 0 { - w.current.header.ShardStateHash = shardState.Hash() + w.current.header.SetShardStateHash(shardState.Hash()) shardStateData, err := rlp.EncodeToBytes(shardState) if err == nil { - w.current.header.ShardState = shardStateData + w.current.header.SetShardState(shardStateData) } else { utils.Logger().Debug().Err(err).Msg("Failed to encode proposed shard state") return nil, err @@ -350,21 +353,21 @@ func New(config *params.ChainConfig, chain *core.BlockChain, engine consensus_en num := parent.Number() timestamp := time.Now().Unix() // New block's epoch is the same as parent's... - epoch := new(big.Int).Set(parent.Header().Epoch) + epoch := parent.Header().Epoch() // TODO: Don't depend on sharding state for epoch change. - if len(parent.Header().ShardState) > 0 && parent.NumberU64() != 0 { + if len(parent.Header().ShardState()) > 0 && parent.NumberU64() != 0 { // ... except if parent has a resharding assignment it increases by 1. epoch = epoch.Add(epoch, common.Big1) } - header := &block.Header{ - ParentHash: parent.Hash(), - Number: num.Add(num, common.Big1), - GasLimit: core.CalcGasLimit(parent, worker.gasFloor, worker.gasCeil), - Time: big.NewInt(timestamp), - Epoch: epoch, - ShardID: worker.chain.ShardID(), - } + header := block.NewHeaderWith(). + ParentHash(parent.Hash()). + Number(num.Add(num, common.Big1)). + GasLimit(core.CalcGasLimit(parent, worker.gasFloor, worker.gasCeil)). + Time(big.NewInt(timestamp)). + Epoch(epoch). + ShardID(worker.chain.ShardID()). + Header() worker.makeCurrent(parent, header) return worker diff --git a/shard/shard_state.go b/shard/shard_state.go index 09846dc4d..6e0d11358 100644 --- a/shard/shard_state.go +++ b/shard/shard_state.go @@ -174,8 +174,8 @@ func GetHashFromNodeList(nodeList []NodeID) []byte { } d := sha3.NewLegacyKeccak256() - for i := range nodeList { - d.Write(nodeList[i].Serialize()) + for _, nodeID := range nodeList { + d.Write(nodeID.Serialize()) } return d.Sum(nil) }