fix block encoding/decoding issue for blockV2 and headerV3

pull/1795/head
chao 5 years ago
parent d49dafa85e
commit 99ab46c6ef
  1. 415
      block/v3/header.go
  2. 5
      consensus/consensus_v2.go
  3. 2
      core/blockchain.go
  4. 2
      core/state_processor.go
  5. 3
      core/types/block.go
  6. 8
      core/types/bodyv0.go
  7. 8
      core/types/bodyv1.go
  8. 4
      internal/params/config.go
  9. 3
      node/node_newblock.go
  10. 1
      node/worker/worker.go

@ -1,16 +1,421 @@
package v3 package v3
import ( import (
v2 "github.com/harmony-one/harmony/block/v2" "io"
"math/big"
"unsafe"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/rs/zerolog"
blockif "github.com/harmony-one/harmony/block/interface"
"github.com/harmony-one/harmony/crypto/hash"
"github.com/harmony-one/harmony/shard"
) )
// Header v3 has the same structure as v2 header // Header is the V3 block header.
// It is used to identify the body v3 which including staking txs // V3 block header is exactly the same
// we copy the code instead of embedded v2 header into v3
// when we do type checking in NewBodyForMatchingHeader
// the embedded structure will return v2 header type instead of v3 type
type Header struct { type Header struct {
v2.Header 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. // NewHeader creates a new header object.
func NewHeader() *Header { func NewHeader() *Header {
return &Header{*v2.NewHeader()} 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"`
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
OutgoingReceiptHash common.Hash `json:"outgoingReceiptsRoot" gencodec:"required"`
IncomingReceiptHash common.Hash `json:"incomingReceiptsRoot" gencodec:"required"`
Bloom ethtypes.Bloom `json:"logsBloom" gencodec:"required"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Time *big.Int `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash" gencodec:"required"`
// Additional Fields
ViewID *big.Int `json:"viewID" gencodec:"required"`
Epoch *big.Int `json:"epoch" gencodec:"required"`
ShardID uint32 `json:"shardID" gencodec:"required"`
LastCommitSignature [96]byte `json:"lastCommitSignature" gencodec:"required"`
LastCommitBitmap []byte `json:"lastCommitBitmap" gencodec:"required"` // Contains which validator signed
ShardStateHash common.Hash `json:"shardStateRoot"`
Vrf []byte `json:"vrf"`
Vdf []byte `json:"vdf"`
ShardState []byte `json:"shardState"`
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() ethtypes.Bloom {
return h.fields.Bloom
}
// SetBloom sets the smart contract log Bloom filter for this block.
func (h *Header) SetBloom(newBloom ethtypes.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
Number *hexutil.Big
GasLimit hexutil.Uint64
GasUsed hexutil.Uint64
Time *hexutil.Big
Extra hexutil.Bytes
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
}
// Hash returns the block hash of the header, which is simply the keccak256 hash of its
// RLP encoding.
func (h *Header) Hash() common.Hash {
return hash.FromRLP(h)
}
// Size returns the approximate memory used by all internal contents. It is used
// 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)
}
// Logger returns a sub-logger with block contexts added.
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()).
Logger()
return &nlogger
}
// GetShardState returns the deserialized shard state object.
func (h *Header) GetShardState() (shard.State, error) {
shardState := shard.State{}
err := rlp.DecodeBytes(h.ShardState(), &shardState)
if err != nil {
return nil, err
}
return shardState, nil
}
// Copy returns a copy of the given header.
func (h *Header) Copy() blockif.Header {
cpy := *h
return &cpy
} }

@ -95,17 +95,12 @@ func (consensus *Consensus) announce(block *types.Block) {
utils.Logger().Debug().Msg("[Announce] Failed encoding block") utils.Logger().Debug().Msg("[Announce] Failed encoding block")
return return
} }
utils.Logger().Debug().Msgf("haha1, before:%v ", len(block.StakingTransactions()))
encodedBlockHeader, err := rlp.EncodeToBytes(block.Header()) encodedBlockHeader, err := rlp.EncodeToBytes(block.Header())
if err != nil { if err != nil {
utils.Logger().Debug().Msg("[Announce] Failed encoding block header") utils.Logger().Debug().Msg("[Announce] Failed encoding block header")
return return
} }
var blockObj1 types.Block
err = rlp.DecodeBytes(encodedBlock, &blockObj1)
utils.Logger().Debug().Msgf("haha2, after stks:= %v", len(blockObj1.StakingTransactions()))
consensus.block = encodedBlock consensus.block = encodedBlock
consensus.blockHeader = encodedBlockHeader consensus.blockHeader = encodedBlockHeader
msgToSend := consensus.constructAnnounceMessage() msgToSend := consensus.constructAnnounceMessage()

@ -229,14 +229,12 @@ func (bc *BlockChain) ValidateNewBlock(block *types.Block) error {
// Process block using the parent state as reference point. // Process block using the parent state as reference point.
receipts, cxReceipts, _, usedGas, err := bc.processor.Process(block, state, bc.vmConfig) receipts, cxReceipts, _, usedGas, err := bc.processor.Process(block, state, bc.vmConfig)
if err != nil { if err != nil {
utils.Logger().Info().Msgf("hehe1, usedGas: %v, err: %v", usedGas, err)
bc.reportBlock(block, receipts, err) bc.reportBlock(block, receipts, err)
return err return err
} }
err = bc.Validator().ValidateState(block, bc.CurrentBlock(), state, receipts, cxReceipts, usedGas) err = bc.Validator().ValidateState(block, bc.CurrentBlock(), state, receipts, cxReceipts, usedGas)
if err != nil { if err != nil {
utils.Logger().Info().Msgf("hehe2, err: %v", err)
bc.reportBlock(block, receipts, err) bc.reportBlock(block, receipts, err)
return err return err
} }

@ -88,12 +88,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.DB, cfg vm.C
// Iterate over staking transactions // Iterate over staking transactions
L := len(block.Transactions()) L := len(block.Transactions())
utils.Logger().Info().Msgf("oops: len stakingTx : %v", len(block.StakingTransactions()))
for i, tx := range block.StakingTransactions() { for i, tx := range block.StakingTransactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i+L) statedb.Prepare(tx.Hash(), block.Hash(), i+L)
receipt, _, err := receipt, _, err :=
ApplyStakingTransaction(p.config, p.bc, &coinbase, gp, statedb, header, tx, usedGas, cfg) ApplyStakingTransaction(p.config, p.bc, &coinbase, gp, statedb, header, tx, usedGas, cfg)
utils.Logger().Info().Msgf("hehe, i: %v, usedGas: %v, err: %v", i, *usedGas, err)
if err != nil { if err != nil {
return nil, nil, nil, 0, err return nil, nil, nil, 0, err

@ -83,6 +83,9 @@ type BodyInterface interface {
// Transactions returns a deep copy the list of transactions in this block. // Transactions returns a deep copy the list of transactions in this block.
Transactions() []*Transaction Transactions() []*Transaction
// StakingTransactions returns a deep copy of staking transactions
StakingTransactions() []*staking.StakingTransaction
// TransactionAt returns the transaction at the given index in this block. // TransactionAt returns the transaction at the given index in this block.
// It returns nil if index is out of bounds. // It returns nil if index is out of bounds.
TransactionAt(index int) *Transaction TransactionAt(index int) *Transaction

@ -7,6 +7,7 @@ import (
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/utils"
staking "github.com/harmony-one/harmony/staking/types"
) )
// BodyV0 is the V0 block body // BodyV0 is the V0 block body
@ -79,6 +80,13 @@ func (b *BodyV0) IncomingReceipts() (incomingReceipts CXReceiptsProofs) {
return nil return nil
} }
// StakingTransactions returns the list of staking transactions.
// The returned list is a deep copy; the caller may do anything with it without
// affecting the original.
func (b *BodyV0) StakingTransactions() (txs []*staking.StakingTransaction) {
return nil
}
// SetIncomingReceipts sets the list of incoming cross-shard transaction // SetIncomingReceipts sets the list of incoming cross-shard transaction
// receipts of this block with a dep copy of the given list. // receipts of this block with a dep copy of the given list.
func (b *BodyV0) SetIncomingReceipts(newIncomingReceipts CXReceiptsProofs) { func (b *BodyV0) SetIncomingReceipts(newIncomingReceipts CXReceiptsProofs) {

@ -6,6 +6,7 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
staking "github.com/harmony-one/harmony/staking/types"
) )
// BodyV1 is the V1 block body // BodyV1 is the V1 block body
@ -30,6 +31,13 @@ func (b *BodyV1) Transactions() (txs []*Transaction) {
return txs return txs
} }
// StakingTransactions returns the list of staking transactions.
// The returned list is a deep copy; the caller may do anything with it without
// affecting the original.
func (b *BodyV1) StakingTransactions() (txs []*staking.StakingTransaction) {
return nil
}
// TransactionAt returns the transaction at the given index in this block. // TransactionAt returns the transaction at the given index in this block.
// It returns nil if index is out of bounds. // It returns nil if index is out of bounds.
func (b *BodyV1) TransactionAt(index int) *Transaction { func (b *BodyV1) TransactionAt(index int) *Transaction {

@ -35,8 +35,8 @@ var (
TestnetChainConfig = &ChainConfig{ TestnetChainConfig = &ChainConfig{
ChainID: TestnetChainID, ChainID: TestnetChainID,
CrossTxEpoch: big.NewInt(0), CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: EpochTBD, CrossLinkEpoch: big.NewInt(0),
StakingEpoch: EpochTBD, StakingEpoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0), EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0), S3Epoch: big.NewInt(0),
} }

@ -82,9 +82,6 @@ func (node *Node) proposeNewBlock() (*types.Block, error) {
// Prepare transactions including staking transactions // Prepare transactions including staking transactions
selectedTxs, selectedStakingTxs := node.getTransactionsForNewBlock(coinbase) selectedTxs, selectedStakingTxs := node.getTransactionsForNewBlock(coinbase)
if len(selectedStakingTxs) > 0 {
utils.Logger().Debug().Int("selectedStakingtxs", len(selectedStakingTxs)).Msg("hehe, staking txs proposed")
}
if err := node.Worker.CommitTransactions(selectedTxs, selectedStakingTxs, coinbase); err != nil { if err := node.Worker.CommitTransactions(selectedTxs, selectedStakingTxs, coinbase); err != nil {
ctxerror.Log15(utils.GetLogger().Error, ctxerror.Log15(utils.GetLogger().Error,

@ -426,7 +426,6 @@ func (w *Worker) FinalizeNewBlock(sig []byte, signers []byte, viewID uint64, coi
return nil, ctxerror.New("cannot finalize block").WithCause(err) return nil, ctxerror.New("cannot finalize block").WithCause(err)
} }
utils.Logger().Debug().Msgf("hehehe, len stxs: %v", len(block.StakingTransactions()))
return block, nil return block, nil
} }

Loading…
Cancel
Save