github.com/ava-labs/avalanchego@v1.11.11/vms/proposervm/block/parse_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package block 5 6 import ( 7 "crypto" 8 "encoding/hex" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/require" 13 14 "github.com/ava-labs/avalanchego/codec" 15 "github.com/ava-labs/avalanchego/ids" 16 "github.com/ava-labs/avalanchego/staking" 17 "github.com/ava-labs/avalanchego/utils/wrappers" 18 ) 19 20 func TestParseBlocks(t *testing.T) { 21 parentID := ids.ID{1} 22 timestamp := time.Unix(123, 0) 23 pChainHeight := uint64(2) 24 innerBlockBytes := []byte{3} 25 chainID := ids.ID{4} 26 27 tlsCert, err := staking.NewTLSCert() 28 require.NoError(t, err) 29 30 cert, err := staking.ParseCertificate(tlsCert.Leaf.Raw) 31 require.NoError(t, err) 32 key := tlsCert.PrivateKey.(crypto.Signer) 33 34 signedBlock, err := Build( 35 parentID, 36 timestamp, 37 pChainHeight, 38 cert, 39 innerBlockBytes, 40 chainID, 41 key, 42 ) 43 require.NoError(t, err) 44 45 signedBlockBytes := signedBlock.Bytes() 46 malformedBlockBytes := make([]byte, len(signedBlockBytes)-1) 47 copy(malformedBlockBytes, signedBlockBytes) 48 49 for _, testCase := range []struct { 50 name string 51 input [][]byte 52 output []ParseResult 53 }{ 54 { 55 name: "ValidThenInvalid", 56 input: [][]byte{signedBlockBytes, malformedBlockBytes}, 57 output: []ParseResult{{Block: &statelessBlock{bytes: signedBlockBytes}}, {Err: wrappers.ErrInsufficientLength}}, 58 }, 59 { 60 name: "InvalidThenValid", 61 input: [][]byte{malformedBlockBytes, signedBlockBytes}, 62 output: []ParseResult{{Err: wrappers.ErrInsufficientLength}, {Block: &statelessBlock{bytes: signedBlockBytes}}}, 63 }, 64 } { 65 t.Run(testCase.name, func(t *testing.T) { 66 results := ParseBlocks(testCase.input, chainID) 67 for i := range testCase.output { 68 if testCase.output[i].Block == nil { 69 require.Nil(t, results[i].Block) 70 require.ErrorIs(t, results[i].Err, testCase.output[i].Err) 71 } else { 72 require.Equal(t, testCase.output[i].Block.Bytes(), results[i].Block.Bytes()) 73 require.NoError(t, results[i].Err) 74 } 75 } 76 }) 77 } 78 } 79 80 func TestParse(t *testing.T) { 81 parentID := ids.ID{1} 82 timestamp := time.Unix(123, 0) 83 pChainHeight := uint64(2) 84 innerBlockBytes := []byte{3} 85 chainID := ids.ID{4} 86 87 tlsCert, err := staking.NewTLSCert() 88 require.NoError(t, err) 89 90 cert, err := staking.ParseCertificate(tlsCert.Leaf.Raw) 91 require.NoError(t, err) 92 key := tlsCert.PrivateKey.(crypto.Signer) 93 94 signedBlock, err := Build( 95 parentID, 96 timestamp, 97 pChainHeight, 98 cert, 99 innerBlockBytes, 100 chainID, 101 key, 102 ) 103 require.NoError(t, err) 104 105 unsignedBlock, err := BuildUnsigned(parentID, timestamp, pChainHeight, innerBlockBytes) 106 require.NoError(t, err) 107 108 signedWithoutCertBlockIntf, err := BuildUnsigned(parentID, timestamp, pChainHeight, innerBlockBytes) 109 require.NoError(t, err) 110 signedWithoutCertBlock := signedWithoutCertBlockIntf.(*statelessBlock) 111 signedWithoutCertBlock.Signature = []byte{5} 112 113 signedWithoutCertBlock.bytes, err = Codec.Marshal(CodecVersion, &signedWithoutCertBlockIntf) 114 require.NoError(t, err) 115 116 optionBlock, err := BuildOption(parentID, innerBlockBytes) 117 require.NoError(t, err) 118 119 tests := []struct { 120 name string 121 block Block 122 chainID ids.ID 123 expectedErr error 124 }{ 125 { 126 name: "correct chainID", 127 block: signedBlock, 128 chainID: chainID, 129 expectedErr: nil, 130 }, 131 { 132 name: "invalid chainID", 133 block: signedBlock, 134 chainID: ids.ID{5}, 135 expectedErr: staking.ErrECDSAVerificationFailure, 136 }, 137 { 138 name: "unsigned block", 139 block: unsignedBlock, 140 chainID: chainID, 141 expectedErr: nil, 142 }, 143 { 144 name: "invalid signature", 145 block: signedWithoutCertBlockIntf, 146 chainID: chainID, 147 expectedErr: errUnexpectedSignature, 148 }, 149 { 150 name: "option block", 151 block: optionBlock, 152 chainID: chainID, 153 expectedErr: nil, 154 }, 155 } 156 for _, test := range tests { 157 t.Run(test.name, func(t *testing.T) { 158 require := require.New(t) 159 160 blockBytes := test.block.Bytes() 161 parsedBlockWithoutVerification, err := ParseWithoutVerification(blockBytes) 162 require.NoError(err) 163 equal(require, test.block, parsedBlockWithoutVerification) 164 165 parsedBlock, err := Parse(blockBytes, test.chainID) 166 require.ErrorIs(err, test.expectedErr) 167 if test.expectedErr == nil { 168 equal(require, test.block, parsedBlock) 169 } 170 }) 171 } 172 } 173 174 func TestParseBytes(t *testing.T) { 175 chainID := ids.ID{4} 176 tests := []struct { 177 name string 178 hex string 179 expectedErr error 180 }{ 181 { 182 name: "duplicate extensions in certificate", 183 hex: "0000000000000100000000000000000000000000000000000000000000000000000000000000000000000000007b0000000000000002000004bd308204b9308202a1a003020102020100300d06092a864886f70d01010b050030003020170d3939313233313030303030305a180f32313232303830333233323835335a300030820222300d06092a864886f70d01010105000382020f003082020a0282020100c2b2de1c16924d9b9254a0d5b80a4bc5f9beaa4f4f40a0e4efb69eb9b55d7d37f8c82328c237d7c5b451f5427b487284fa3f365f9caa53c7fcfef8d7a461d743bd7d88129f2da62b877ebe9d6feabf1bd12923e6c12321382c782fc3bb6b6cb4986a937a1edc3814f4e621e1a62053deea8c7649e43edd97ab6b56315b00d9ab5026bb9c31fb042dc574ba83c54e720e0120fcba2e8a66b77839be3ece0d4a6383ef3f76aac952b49a15b65e18674cd1340c32cecbcbaf80ae45be001366cb56836575fb0ab51ea44bf7278817e99b6b180fdd110a49831a132968489822c56692161bbd372cf89d9b8ee5a734cff15303b3a960ee78d79e76662a701941d9ec084429f26707f767e9b1d43241c0e4f96655d95c1f4f4aa00add78eff6bf0a6982766a035bf0b465786632c5bb240788ca0fdf032d8815899353ea4bec5848fd30118711e5b356bde8a0da074cc25709623225e734ff5bd0cf65c40d9fd8fccf746d8f8f35145bcebcf378d2b086e57d78b11e84f47fa467c4d037f92bff6dd4e934e0189b58193f24c4222ffb72b5c06361cf68ca64345bc3e230cc0f40063ad5f45b1659c643662996328c2eeddcd760d6f7c9cbae081ccc065844f7ea78c858564a408979764de882793706acc67d88092790dff567ed914b03355330932616a0f26f994b963791f0b1dbd8df979db86d1ea490700a3120293c3c2b10bef10203010001a33c303a300e0603551d0f0101ff0404030204b030130603551d25040c300a06082b0601050507030230130603551d25040c300a06082b06010505070302300d06092a864886f70d01010b05000382020100a21a0d73ec9ef4eb39f810557ac70b0b775772b8bae5f42c98565bc50b5b2c57317aa9cb1da12f55d0aac7bb36a00cd4fd0d7384c4efa284b53520c5a3c4b8a65240b393eeab02c802ea146c0728c3481c9e8d3aaad9d4dd7607103dcfaa96da83460adbe18174ed5b71bde7b0a93d4fb52234a9ff54e3fd25c5b74790dfb090f2e59dc5907357f510cc3a0b70ccdb87aee214def794b316224f318b471ffa13b66e44b467670e881cb1628c99c048a503376d9b6d7b8eef2e7be47ff7d5c1d56221f4cf7fa2519b594cb5917815c64dc75d8d281bcc99b5a12899b08f2ca0f189857b64a1afc5963337f3dd6e79390e85221569f6dbbb13aadce06a3dfb5032f0cc454809627872cd7cd0cea5eba187723f07652c8abc3fc42bd62136fc66287f2cc19a7cb416923ad1862d7f820b55cacb65e43731cb6df780e2651e457a3438456aeeeb278ad9c0ad2e760f6c1cbe276eeb621c8a4e609b5f2d902beb3212e3e45df99497021ff536d0b56390c5d785a8bf7909f6b61bdc705d7d92ae22f58e7b075f164a0450d82d8286bf449072751636ab5185f59f518b845a75d112d6f7b65223479202cff67635e2ad88106bc8a0cc9352d87c5b182ac19a4680a958d814a093acf46730f87da0df6926291d02590f215041b44a0a1a32eeb3a52cddabc3d256689bace18a8d85e644cf9137cce3718f7caac1cb16ae06e874f4c701000000010300000200b8e3a4d9a4394bac714cb597f5ba1a81865185e35c782d0317e7abc0b52d49ff8e10f787bedf86f08148e3dbd2d2d478caa2a2893d31db7d5ee51339883fe84d3004440f16cb3797a7fab0f627d3ebd79217e995488e785cd6bb7b96b9d306f8109daa9cfc4162f9839f60fb965bcb3b56a5fa787549c153a4c80027398f73a617b90b7f24f437b140cd3ac832c0b75ec98b9423b275782988a9fd426937b8f82fbb0e88a622934643fb6335c1a080a4d13125544b04585d5f5295be7cd2c8be364246ea3d5df3e837b39a85074575a1fa2f4799050460110bdfb20795c8a9172a20f61b95e1c5c43eccd0c2c155b67385366142c63409cb3fb488e7aba6c8930f7f151abf1c24a54bd21c3f7a06856ea9db35beddecb30d2c61f533a3d0590bdbb438c6f2a2286dfc3c71b383354f0abad72771c2cc3687b50c2298783e53857cf26058ed78d0c1cf53786eb8d006a058ee3c85a7b2b836b5d03ef782709ce8f2725548e557b3de45a395a669a15f1d910e97015d22ac70020cab7e2531e8b1f739b023b49e742203e9e19a7fe0053826a9a2fe2e118d3b83498c2cb308573202ad41aa4a390aee4b6b5dd2164e5c5cd1b5f68b7d5632cf7dbb9a9139663c9aac53a74b2c6fc73cad80e228a186ba027f6f32f0182d62503e04fcced385f2e7d2e11c00940622ebd533b4d144689082f9777e5b16c36f9af9066e0ad6564d43", 184 expectedErr: nil, 185 }, 186 { 187 name: "gibberish", 188 hex: "000102030405", 189 expectedErr: codec.ErrUnknownVersion, 190 }, 191 } 192 for _, test := range tests { 193 t.Run(test.name, func(t *testing.T) { 194 require := require.New(t) 195 196 bytes, err := hex.DecodeString(test.hex) 197 require.NoError(err) 198 199 _, err = Parse(bytes, chainID) 200 require.ErrorIs(err, test.expectedErr) 201 }) 202 } 203 } 204 205 func TestParseHeader(t *testing.T) { 206 require := require.New(t) 207 208 chainID := ids.ID{1} 209 parentID := ids.ID{2} 210 bodyID := ids.ID{3} 211 212 builtHeader, err := BuildHeader( 213 chainID, 214 parentID, 215 bodyID, 216 ) 217 require.NoError(err) 218 219 builtHeaderBytes := builtHeader.Bytes() 220 221 parsedHeader, err := ParseHeader(builtHeaderBytes) 222 require.NoError(err) 223 224 equalHeader(require, builtHeader, parsedHeader) 225 }