github.com/ethereum-optimism/optimism@v1.7.2/op-node/rollup/derive/engine_consolidate_test.go (about) 1 package derive 2 3 import ( 4 "math/rand" 5 "testing" 6 7 "github.com/ethereum-optimism/optimism/op-node/rollup" 8 "github.com/ethereum-optimism/optimism/op-service/eth" 9 10 "github.com/ethereum-optimism/optimism/op-service/testlog" 11 "github.com/ethereum-optimism/optimism/op-service/testutils" 12 "github.com/ethereum/go-ethereum/common" 13 "github.com/ethereum/go-ethereum/common/hexutil" 14 "github.com/ethereum/go-ethereum/core/types" 15 "github.com/ethereum/go-ethereum/log" 16 "github.com/stretchr/testify/require" 17 ) 18 19 var ( 20 validParentHash = common.HexToHash("0x123") 21 validTimestamp = eth.Uint64Quantity(123) 22 validParentBeaconRoot = common.HexToHash("0x456") 23 validPrevRandao = eth.Bytes32(common.HexToHash("0x789")) 24 validGasLimit = eth.Uint64Quantity(1000) 25 validWithdrawals = types.Withdrawals{} 26 ) 27 28 type args struct { 29 envelope *eth.ExecutionPayloadEnvelope 30 attrs *eth.PayloadAttributes 31 parentHash common.Hash 32 } 33 34 func ecotoneArgs() args { 35 return args{ 36 envelope: ð.ExecutionPayloadEnvelope{ 37 ParentBeaconBlockRoot: &validParentBeaconRoot, 38 ExecutionPayload: ð.ExecutionPayload{ 39 ParentHash: validParentHash, 40 Timestamp: validTimestamp, 41 PrevRandao: validPrevRandao, 42 GasLimit: validGasLimit, 43 Withdrawals: &validWithdrawals, 44 }, 45 }, 46 attrs: ð.PayloadAttributes{ 47 Timestamp: validTimestamp, 48 PrevRandao: validPrevRandao, 49 GasLimit: &validGasLimit, 50 ParentBeaconBlockRoot: &validParentBeaconRoot, 51 Withdrawals: &validWithdrawals, 52 }, 53 parentHash: validParentHash, 54 } 55 } 56 57 func canyonArgs() args { 58 args := ecotoneArgs() 59 args.attrs.ParentBeaconBlockRoot = nil 60 args.envelope.ParentBeaconBlockRoot = nil 61 return args 62 } 63 64 func bedrockArgs() args { 65 args := ecotoneArgs() 66 args.attrs.Withdrawals = nil 67 args.envelope.ExecutionPayload.Withdrawals = nil 68 return args 69 } 70 71 func ecotoneNoParentBeaconBlockRoot() args { 72 args := ecotoneArgs() 73 args.envelope.ParentBeaconBlockRoot = nil 74 return args 75 } 76 77 func ecotoneUnexpectedParentBeaconBlockRoot() args { 78 args := ecotoneArgs() 79 args.attrs.ParentBeaconBlockRoot = nil 80 return args 81 } 82 83 func ecotoneMismatchParentBeaconBlockRoot() args { 84 args := ecotoneArgs() 85 h := common.HexToHash("0xabc") 86 args.attrs.ParentBeaconBlockRoot = &h 87 return args 88 } 89 90 func ecotoneMismatchParentBeaconBlockRootPtr() args { 91 args := ecotoneArgs() 92 cpy := *args.attrs.ParentBeaconBlockRoot 93 args.attrs.ParentBeaconBlockRoot = &cpy 94 return args 95 } 96 97 func ecotoneNilParentBeaconBlockRoots() args { 98 args := ecotoneArgs() 99 args.attrs.ParentBeaconBlockRoot = nil 100 args.envelope.ParentBeaconBlockRoot = nil 101 return args 102 } 103 104 func mismatchedParentHashArgs() args { 105 args := ecotoneArgs() 106 args.parentHash = common.HexToHash("0xabc") 107 return args 108 } 109 110 func createMistmatchedPrevRandao() args { 111 args := ecotoneArgs() 112 args.attrs.PrevRandao = eth.Bytes32(common.HexToHash("0xabc")) 113 return args 114 } 115 116 func createMismatchedGasLimit() args { 117 args := ecotoneArgs() 118 val := eth.Uint64Quantity(2000) 119 args.attrs.GasLimit = &val 120 return args 121 } 122 123 func createNilGasLimit() args { 124 args := ecotoneArgs() 125 args.attrs.GasLimit = nil 126 return args 127 } 128 129 func createMistmatchedTimestamp() args { 130 args := ecotoneArgs() 131 val := eth.Uint64Quantity(2000) 132 args.attrs.Timestamp = val 133 return args 134 } 135 136 func TestAttributesMatch(t *testing.T) { 137 rollupCfg := &rollup.Config{} 138 139 tests := []struct { 140 shouldMatch bool 141 args args 142 }{ 143 { 144 shouldMatch: true, 145 args: ecotoneArgs(), 146 }, 147 { 148 shouldMatch: true, 149 args: canyonArgs(), 150 }, 151 { 152 shouldMatch: true, 153 args: bedrockArgs(), 154 }, 155 { 156 shouldMatch: false, 157 args: mismatchedParentHashArgs(), 158 }, 159 { 160 shouldMatch: false, 161 args: ecotoneNoParentBeaconBlockRoot(), 162 }, 163 { 164 shouldMatch: false, 165 args: ecotoneUnexpectedParentBeaconBlockRoot(), 166 }, 167 { 168 shouldMatch: false, 169 args: ecotoneMismatchParentBeaconBlockRoot(), 170 }, 171 { 172 shouldMatch: true, 173 args: ecotoneMismatchParentBeaconBlockRootPtr(), 174 }, 175 { 176 shouldMatch: true, 177 args: ecotoneNilParentBeaconBlockRoots(), 178 }, 179 { 180 shouldMatch: false, 181 args: createMistmatchedPrevRandao(), 182 }, 183 { 184 shouldMatch: false, 185 args: createMismatchedGasLimit(), 186 }, 187 { 188 shouldMatch: false, 189 args: createNilGasLimit(), 190 }, 191 { 192 shouldMatch: false, 193 args: createMistmatchedTimestamp(), 194 }, 195 } 196 197 for _, test := range tests { 198 err := AttributesMatchBlock(rollupCfg, test.args.attrs, test.args.parentHash, test.args.envelope, testlog.Logger(t, log.LevelInfo)) 199 if test.shouldMatch { 200 require.NoError(t, err) 201 } else { 202 require.Error(t, err) 203 } 204 } 205 } 206 207 func TestWithdrawalsMatch(t *testing.T) { 208 tests := []struct { 209 attrs *types.Withdrawals 210 block *types.Withdrawals 211 shouldMatch bool 212 }{ 213 { 214 attrs: nil, 215 block: nil, 216 shouldMatch: true, 217 }, 218 { 219 attrs: &types.Withdrawals{}, 220 block: nil, 221 shouldMatch: false, 222 }, 223 { 224 attrs: nil, 225 block: &types.Withdrawals{}, 226 shouldMatch: false, 227 }, 228 { 229 attrs: &types.Withdrawals{}, 230 block: &types.Withdrawals{}, 231 shouldMatch: true, 232 }, 233 { 234 attrs: &types.Withdrawals{ 235 { 236 Index: 1, 237 }, 238 }, 239 block: &types.Withdrawals{}, 240 shouldMatch: false, 241 }, 242 { 243 attrs: &types.Withdrawals{ 244 { 245 Index: 1, 246 }, 247 }, 248 block: &types.Withdrawals{ 249 { 250 Index: 2, 251 }, 252 }, 253 shouldMatch: false, 254 }, 255 } 256 257 for _, test := range tests { 258 err := checkWithdrawalsMatch(test.attrs, test.block) 259 260 if test.shouldMatch { 261 require.NoError(t, err) 262 } else { 263 require.Error(t, err) 264 } 265 } 266 } 267 268 func TestGetMissingTxnHashes(t *testing.T) { 269 depositTxs := make([]*types.Transaction, 5) 270 271 for i := 0; i < len(depositTxs); i++ { 272 rng := rand.New(rand.NewSource(1234 + int64(i))) 273 safeDeposit := testutils.GenerateDeposit(testutils.RandomHash(rng), rng) 274 depositTxs[i] = types.NewTx(safeDeposit) 275 } 276 277 tests := []struct { 278 safeTransactions []hexutil.Bytes 279 unsafeTransactions []hexutil.Bytes 280 expectedSafeMissingHashes []common.Hash 281 expectedUnsafeMissingHashes []common.Hash 282 expectErr bool 283 }{ 284 { 285 safeTransactions: []hexutil.Bytes{}, 286 unsafeTransactions: []hexutil.Bytes{depositTxToBytes(t, depositTxs[0])}, 287 expectedSafeMissingHashes: []common.Hash{depositTxs[0].Hash()}, 288 expectedUnsafeMissingHashes: []common.Hash{}, 289 expectErr: false, 290 }, 291 { 292 safeTransactions: []hexutil.Bytes{depositTxToBytes(t, depositTxs[0])}, 293 unsafeTransactions: []hexutil.Bytes{}, 294 expectedSafeMissingHashes: []common.Hash{}, 295 expectedUnsafeMissingHashes: []common.Hash{depositTxs[0].Hash()}, 296 expectErr: false, 297 }, 298 { 299 safeTransactions: []hexutil.Bytes{ 300 depositTxToBytes(t, depositTxs[0]), 301 }, 302 unsafeTransactions: []hexutil.Bytes{ 303 depositTxToBytes(t, depositTxs[0]), 304 depositTxToBytes(t, depositTxs[1]), 305 depositTxToBytes(t, depositTxs[2]), 306 }, 307 expectedSafeMissingHashes: []common.Hash{ 308 depositTxs[1].Hash(), 309 depositTxs[2].Hash(), 310 }, 311 expectedUnsafeMissingHashes: []common.Hash{}, 312 expectErr: false, 313 }, 314 { 315 safeTransactions: []hexutil.Bytes{ 316 depositTxToBytes(t, depositTxs[0]), 317 depositTxToBytes(t, depositTxs[1]), 318 depositTxToBytes(t, depositTxs[2]), 319 }, 320 unsafeTransactions: []hexutil.Bytes{ 321 depositTxToBytes(t, depositTxs[0]), 322 }, 323 expectedSafeMissingHashes: []common.Hash{}, 324 expectedUnsafeMissingHashes: []common.Hash{ 325 depositTxs[1].Hash(), 326 depositTxs[2].Hash(), 327 }, 328 expectErr: false, 329 }, 330 { 331 safeTransactions: []hexutil.Bytes{ 332 depositTxToBytes(t, depositTxs[0]), 333 depositTxToBytes(t, depositTxs[1]), 334 depositTxToBytes(t, depositTxs[2]), 335 }, 336 unsafeTransactions: []hexutil.Bytes{ 337 depositTxToBytes(t, depositTxs[2]), 338 depositTxToBytes(t, depositTxs[3]), 339 depositTxToBytes(t, depositTxs[4]), 340 }, 341 expectedSafeMissingHashes: []common.Hash{ 342 depositTxs[3].Hash(), 343 depositTxs[4].Hash(), 344 }, 345 expectedUnsafeMissingHashes: []common.Hash{ 346 depositTxs[0].Hash(), 347 depositTxs[1].Hash(), 348 }, 349 expectErr: false, 350 }, 351 { 352 safeTransactions: []hexutil.Bytes{{1, 2, 3}}, 353 unsafeTransactions: []hexutil.Bytes{}, 354 expectedSafeMissingHashes: []common.Hash{}, 355 expectedUnsafeMissingHashes: []common.Hash{}, 356 expectErr: true, 357 }, 358 { 359 safeTransactions: []hexutil.Bytes{}, 360 unsafeTransactions: []hexutil.Bytes{{1, 2, 3}}, 361 expectedSafeMissingHashes: []common.Hash{}, 362 expectedUnsafeMissingHashes: []common.Hash{}, 363 expectErr: true, 364 }, 365 } 366 367 for _, test := range tests { 368 missingSafeHashes, missingUnsafeHashes, err := getMissingTxnHashes( 369 testlog.Logger(t, log.LevelError), 370 test.safeTransactions, 371 test.unsafeTransactions, 372 ) 373 374 if test.expectErr { 375 require.Error(t, err) 376 } else { 377 require.NoError(t, err) 378 require.ElementsMatch(t, test.expectedSafeMissingHashes, missingSafeHashes) 379 require.ElementsMatch(t, test.expectedUnsafeMissingHashes, missingUnsafeHashes) 380 } 381 } 382 } 383 384 func depositTxToBytes(t *testing.T, tx *types.Transaction) hexutil.Bytes { 385 txBytes, err := tx.MarshalBinary() 386 require.NoError(t, err) 387 388 return txBytes 389 }