rollmint icon indicating copy to clipboard operation
rollmint copied to clipboard

Block Serialization round trip test fails with empty Tx or RawRootsList struct(s)

Open jbowen93 opened this issue 3 years ago • 3 comments

Error

Diff:
                                --- Expected
                                +++ Actual
                                @@ -38,7 +38,5 @@
                                  Data: (types.Data) {
                                -  Txs: (types.Txs) {
                                -  },
                                +  Txs: (types.Txs) <nil>,
                                   IntermediateStateRoots: (types.IntermediateStateRoots) {
                                -   RawRootsList: ([][]uint8) {
                                -   }
                                +   RawRootsList: ([][]uint8) <nil>
                                   },

Repro: add this test In types/serialization_test.go Line 60

{"No Txs", &Block{
            Header: Header{
                Version: Version{
                    Block: 1,
                    App:   2,
                },
                NamespaceID:     [8]byte{0, 1, 2, 3, 4, 5, 6, 7},
                Height:          3,
                Time:            4567,
                LastHeaderHash:  h[0],
                LastCommitHash:  h[1],
                DataHash:        h[2],
                ConsensusHash:   h[3],
                AppHash:         h[4],
                LastResultsHash: h[5],
                ProposerAddress: []byte{4, 3, 2, 1},
            },
            Data: Data{
                Txs:                    Txs{},
                IntermediateStateRoots: IntermediateStateRoots{RawRootsList: [][]byte{[]byte{0x1}}},
                // TODO(tzdybal): update when we have actual evidence types
                Evidence: EvidenceData{Evidence: nil},
            },
            LastCommit: Commit{
                Height:     8,
                HeaderHash: h[6],
                Signatures: []Signature{Signature([]byte{1, 1, 1}), Signature([]byte{2, 2, 2})},
            },
        }},

It gives

Diff:
                                --- Expected
                                +++ Actual
                                @@ -40,4 +40,3 @@
                                  Data: (types.Data) {
                                -  Txs: (types.Txs) {
                                -  },
                                +  Txs: (types.Txs) <nil>,
                                   IntermediateStateRoots: (types.IntermediateStateRoots) {
Test:           TestBlockSerializationRoundTrip/No_Txs

I ran into this in the getRandomBlock function of mock_test.go

func getRandomBlock(height uint64, nTxs int) *types.Block {
	block := &types.Block{
		Header: types.Header{
			Height: height,
		},
		Data: types.Data{
			Txs: make(types.Txs, nTxs),
			IntermediateStateRoots: types.IntermediateStateRoots{
				RawRootsList: make([][]byte, nTxs),
			},
		},
	}
	copy(block.Header.AppHash[:], getRandomBytes(32))

	for i := 0; i < nTxs; i++ {
		block.Data.Txs[i] = getRandomTx()
		block.Data.IntermediateStateRoots.RawRootsList[i] = getRandomBytes(32)
	}

	return block
}

I think make(types.Txs, nTxs) and make([][]byte, nTxs) give empty structs when nTxs is 0

The incompatibility is due to how the (b *Block) UnmarshalBinary works in types/serialization.go

func (b *Block) UnmarshalBinary(data []byte) error {
	var pBlock pb.Block
	err := pBlock.Unmarshal(data)
	if err != nil {
		return err
	}
	err = b.FromProto(&pBlock)
	return err
}

jbowen93 avatar Oct 08 '21 21:10 jbowen93

Does modifying txs :

message Data {
	repeated bytes txs = 1 [(gogoproto.nullable) = false];
	repeated bytes intermediate_state_roots = 2;
	repeated tendermint.abci.Evidence evidence = 3;
}

help in anyway? I could be missing something fundamental here but maybe the omitempty tag is responsible ?

Raneet10 avatar Oct 13 '21 11:10 Raneet10

Looks like this doesn't help

WARNING: field Data.Txs is a repeated non-nullable native type, nullable=false has no effect

jbowen93 avatar Oct 13 '21 20:10 jbowen93

This seems like an issue with protobuf treating empty slices and nil values the same when serializing. This is because protobuf automatically uses the omitempty tag when doing buf generate. This seems like it can be fixed by using a custom json marshaller for protobuf. Relevant comment/issue in tendermint: https://github.com/tendermint/tendermint/issues/3882#issuecomment-527374037

Manav-Aggarwal avatar Oct 30 '23 15:10 Manav-Aggarwal