diff --git a/state/state.go b/state/state.go index 5c1b68a2..bb53ac53 100644 --- a/state/state.go +++ b/state/state.go @@ -128,7 +128,7 @@ func (state State) IsEmpty() bool { // MakeBlock builds a block from the current state with the given txs, commit, // and evidence. Note it also takes a proposerAddress because the state does not -// track rounds, and hence doesn't know the correct proposer. TODO: alleviate this! +// track rounds, and hence does not know the correct proposer. TODO: fix this! func (state State) MakeBlock( height int64, txs []types.Tx, @@ -140,29 +140,22 @@ func (state State) MakeBlock( // Build base block with block data. block := types.MakeBlock(height, txs, commit, evidence) - // Fill rest of header with state data. - block.Version = state.Version.Consensus - block.ChainID = state.ChainID - - // Set time + // Set time. + var timestamp time.Time if height == 1 { - block.Time = state.LastBlockTime // genesis time + timestamp = state.LastBlockTime // genesis time } else { - block.Time = MedianTime(commit, state.LastValidators) + timestamp = MedianTime(commit, state.LastValidators) } - block.LastBlockID = state.LastBlockID - block.TotalTxs = state.LastBlockTotalTx + block.NumTxs - - block.ValidatorsHash = state.Validators.Hash() - block.NextValidatorsHash = state.NextValidators.Hash() - block.ConsensusHash = state.ConsensusParams.Hash() - block.AppHash = state.AppHash - block.LastResultsHash = state.LastResultsHash - - // NOTE: we can't use the state.Validators because we don't - // IncrementAccum for rounds there. - block.ProposerAddress = proposerAddress + // Fill rest of header with state data. + block.Header.Populate( + state.Version.Consensus, state.ChainID, + timestamp, state.LastBlockID, state.LastBlockTotalTx+block.NumTxs, + state.Validators.Hash(), state.NextValidators.Hash(), + state.ConsensusParams.Hash(), state.AppHash, state.LastResultsHash, + proposerAddress, + ) return block, block.MakePartSet(types.BlockPartSizeBytes) } diff --git a/types/block.go b/types/block.go index 2a5b5fc4..4d646d4b 100644 --- a/types/block.go +++ b/types/block.go @@ -257,11 +257,11 @@ func MaxDataBytesUnknownEvidence(maxBytes int64, valsCount int) int64 { //----------------------------------------------------------------------------- -// Header defines the structure of a Tendermint block header +// Header defines the structure of a Tendermint block header. // NOTE: changes to the Header should be duplicated in: -// - header.Hash() -// - abci.Header -// - /docs/spec/blockchain/blockchain.md +// - header.Hash() +// - abci.Header +// - /docs/spec/blockchain/blockchain.md type Header struct { // basic block info Version version.Consensus `json:"version"` @@ -290,6 +290,41 @@ type Header struct { ProposerAddress Address `json:"proposer_address"` // original proposer of the block } +func newHeader( + height, numTxs int64, + commitHash, dataHash, evidenceHash []byte, +) *Header { + return &Header{ + Height: height, + NumTxs: numTxs, + LastCommitHash: commitHash, + DataHash: dataHash, + EvidenceHash: evidenceHash, + } +} + +// Populate the Header with state-derived data. +// Call this after MakeBlock to complete the Header. +func (h *Header) Populate( + version version.Consensus, chainID string, + timestamp time.Time, lastBlockID BlockID, totalTxs int64, + valHash, nextValHash []byte, + consensusHash, appHash, lastResultsHash []byte, + proposerAddress Address, +) { + h.Version = version + h.ChainID = chainID + h.Time = timestamp + h.LastBlockID = lastBlockID + h.TotalTxs = totalTxs + h.ValidatorsHash = valHash + h.NextValidatorsHash = nextValHash + h.ConsensusHash = consensusHash + h.AppHash = appHash + h.LastResultsHash = lastResultsHash + h.ProposerAddress = proposerAddress +} + // Hash returns the hash of the header. // It computes a Merkle tree from the header fields // ordered as they appear in the Header. diff --git a/types/protobuf.go b/types/protobuf.go index c9c429c8..e1ec81e8 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -34,6 +34,10 @@ type tm2pb struct{} func (tm2pb) Header(header *Header) abci.Header { return abci.Header{ + Version: abci.Version{ + Block: header.Version.Block.Uint64(), + App: header.Version.App.Uint64(), + }, ChainID: header.ChainID, Height: header.Height, Time: header.Time, @@ -45,10 +49,11 @@ func (tm2pb) Header(header *Header) abci.Header { LastCommitHash: header.LastCommitHash, DataHash: header.DataHash, - ValidatorsHash: header.ValidatorsHash, - ConsensusHash: header.ConsensusHash, - AppHash: header.AppHash, - LastResultsHash: header.LastResultsHash, + ValidatorsHash: header.ValidatorsHash, + NextValidatorsHash: header.NextValidatorsHash, + ConsensusHash: header.ConsensusHash, + AppHash: header.AppHash, + LastResultsHash: header.LastResultsHash, EvidenceHash: header.EvidenceHash, ProposerAddress: header.ProposerAddress, diff --git a/types/protobuf_test.go b/types/protobuf_test.go index f8682abf..39502255 100644 --- a/types/protobuf_test.go +++ b/types/protobuf_test.go @@ -4,12 +4,16 @@ import ( "testing" "time" + "github.com/golang/protobuf/proto" "github.com/stretchr/testify/assert" + + "github.com/tendermint/go-amino" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/secp256k1" - tmtime "github.com/tendermint/tendermint/types/time" + "github.com/tendermint/tendermint/version" ) func TestABCIPubKey(t *testing.T) { @@ -76,16 +80,53 @@ func TestABCIConsensusParams(t *testing.T) { } func TestABCIHeader(t *testing.T) { - header := &Header{ - Height: int64(3), - Time: tmtime.Now(), - NumTxs: int64(10), - ProposerAddress: []byte("cloak"), + // build a full header + var height int64 = 5 + var numTxs int64 = 3 + header := newHeader( + height, numTxs, + []byte("lastCommitHash"), []byte("dataHash"), []byte("evidenceHash"), + ) + protocolVersion := version.Consensus{7, 8} + timestamp := time.Now() + lastBlockID := BlockID{ + Hash: []byte("hash"), + PartsHeader: PartSetHeader{ + Total: 10, + Hash: []byte("hash"), + }, } - abciHeader := TM2PB.Header(header) + var totalTxs int64 = 100 + header.Populate( + protocolVersion, "chainID", + timestamp, lastBlockID, totalTxs, + []byte("valHash"), []byte("nextValHash"), + []byte("consHash"), []byte("appHash"), []byte("lastResultsHash"), + []byte("proposerAddress"), + ) + + cdc := amino.NewCodec() + headerBz := cdc.MustMarshalBinaryBare(header) + + pbHeader := TM2PB.Header(header) + pbHeaderBz, err := proto.Marshal(&pbHeader) + assert.NoError(t, err) + + // assert some fields match + assert.EqualValues(t, protocolVersion.Block, pbHeader.Version.Block) + assert.EqualValues(t, protocolVersion.App, pbHeader.Version.App) + assert.EqualValues(t, "chainID", pbHeader.ChainID) + assert.EqualValues(t, height, pbHeader.Height) + assert.EqualValues(t, timestamp, pbHeader.Time) + assert.EqualValues(t, numTxs, pbHeader.NumTxs) + assert.EqualValues(t, totalTxs, pbHeader.TotalTxs) + assert.EqualValues(t, lastBlockID.Hash, pbHeader.LastBlockId.Hash) + assert.EqualValues(t, []byte("lastCommitHash"), pbHeader.LastCommitHash) + assert.Equal(t, []byte("proposerAddress"), pbHeader.ProposerAddress) + + // assert the encodings match + assert.EqualValues(t, headerBz, pbHeaderBz) - assert.Equal(t, int64(3), abciHeader.Height) - assert.Equal(t, []byte("cloak"), abciHeader.ProposerAddress) } func TestABCIEvidence(t *testing.T) { diff --git a/types/results_test.go b/types/results_test.go index 80803385..7db4c916 100644 --- a/types/results_test.go +++ b/types/results_test.go @@ -43,7 +43,7 @@ func TestABCIResults(t *testing.T) { } } -func TestABCIBytes(t *testing.T) { +func TestABCIrResultsBytes(t *testing.T) { results := NewResults([]*abci.ResponseDeliverTx{ {Code: 0, Data: []byte{}}, {Code: 0, Data: []byte("one")},