Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
63072ca1
Unverified
Commit
63072ca1
authored
Nov 03, 2022
by
Maurelian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-node: add ToB tests
parent
12dc97ab
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
587 additions
and
0 deletions
+587
-0
go.mod
op-node/go.mod
+1
-0
go.sum
op-node/go.sum
+2
-0
batch_tob_test.go
op-node/rollup/derive/batch_tob_test.go
+35
-0
deposit_log_tob_test.go
op-node/rollup/derive/deposit_log_tob_test.go
+211
-0
l1_block_info_tob_test.go
op-node/rollup/derive/l1_block_info_tob_test.go
+72
-0
state_tob_test.go
op-node/rollup/driver/state_tob_test.go
+235
-0
fuzzer_functions.go
op-node/testutils/fuzzerutils/fuzzer_functions.go
+31
-0
No files found.
op-node/go.mod
View file @
63072ca1
...
...
@@ -12,6 +12,7 @@ require (
github.com/ethereum/go-ethereum v1.10.26
github.com/golang/snappy v0.0.4
github.com/google/go-cmp v0.5.8
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
github.com/holiman/uint256 v1.2.0
...
...
op-node/go.sum
View file @
63072ca1
...
...
@@ -250,6 +250,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8 h1:Ep/joEub9YwcjRY6ND3+Y/w0ncE540RtGatVhtZL0/Q=
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
...
...
op-node/rollup/derive/batch_tob_test.go
0 → 100644
View file @
63072ca1
package
derive
import
(
"testing"
"github.com/ethereum-optimism/optimism/op-node/testutils/fuzzerutils"
fuzz
"github.com/google/gofuzz"
"github.com/stretchr/testify/assert"
)
// FuzzBatchRoundTrip executes a fuzz test similar to TestBatchRoundTrip, which tests that arbitrary BatchData will be
// encoded and decoded without loss of its original values.
func
FuzzBatchRoundTrip
(
f
*
testing
.
F
)
{
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
fuzzedData
[]
byte
)
{
// Create our fuzzer wrapper to generate complex values
typeProvider
:=
fuzz
.
NewFromGoFuzz
(
fuzzedData
)
.
NilChance
(
0
)
.
MaxDepth
(
10000
)
.
NumElements
(
0
,
0x100
)
.
AllowUnexportedFields
(
true
)
fuzzerutils
.
AddFuzzerFunctions
(
typeProvider
)
// Create our batch data from fuzzed data
var
batchData
BatchData
typeProvider
.
Fuzz
(
&
batchData
)
// Encode our batch data
enc
,
err
:=
batchData
.
MarshalBinary
()
assert
.
NoError
(
t
,
err
)
// Decode our encoded batch data
var
dec
BatchData
err
=
dec
.
UnmarshalBinary
(
enc
)
assert
.
NoError
(
t
,
err
)
// Ensure the round trip encoding of batch data did not result in data loss
assert
.
Equal
(
t
,
&
batchData
,
&
dec
,
"round trip batch encoding/decoding did not match original values"
)
})
}
op-node/rollup/derive/deposit_log_tob_test.go
0 → 100644
View file @
63072ca1
package
derive
import
(
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum-optimism/optimism/op-node/testutils/fuzzerutils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
fuzz
"github.com/google/gofuzz"
"github.com/stretchr/testify/require"
"math/big"
"testing"
)
// fuzzReceipts is similar to makeReceipts except it uses the fuzzer to populate DepositTx fields.
func
fuzzReceipts
(
typeProvider
*
fuzz
.
Fuzzer
,
blockHash
common
.
Hash
,
depositContractAddr
common
.
Address
)
(
receipts
[]
*
types
.
Receipt
,
expectedDeposits
[]
*
types
.
DepositTx
)
{
// Determine how many receipts to generate (capped)
var
receiptCount
uint64
typeProvider
.
Fuzz
(
&
receiptCount
)
// Cap our receipt count otherwise we might generate for too long and our fuzzer will assume we hung
if
receiptCount
>
0x10
{
receiptCount
=
0x10
}
// Create every receipt we intend to
logIndex
:=
uint
(
0
)
for
i
:=
uint64
(
0
);
i
<
receiptCount
;
i
++
{
// Obtain our fuzz parameters for generating this receipt
var
txReceiptValues
struct
{
GoodReceipt
bool
DepositLogs
[]
bool
}
typeProvider
.
Fuzz
(
&
txReceiptValues
)
// Generate a list of transaction receipts
var
logs
[]
*
types
.
Log
status
:=
types
.
ReceiptStatusSuccessful
if
txReceiptValues
.
GoodReceipt
{
status
=
types
.
ReceiptStatusFailed
}
// Determine if this log will be a deposit log or not and generate it accordingly
for
_
,
isDeposit
:=
range
txReceiptValues
.
DepositLogs
{
var
ev
*
types
.
Log
if
isDeposit
{
// Generate a user deposit source
source
:=
UserDepositSource
{
L1BlockHash
:
blockHash
,
LogIndex
:
uint64
(
logIndex
)}
// Fuzz parameters to construct our deposit log
var
fuzzedDepositInfo
struct
{
FromAddr
*
common
.
Address
ToAddr
*
common
.
Address
Value
*
big
.
Int
Gas
uint64
Data
[]
byte
Mint
*
big
.
Int
}
typeProvider
.
Fuzz
(
&
fuzzedDepositInfo
)
// Create our deposit transaction
dep
:=
&
types
.
DepositTx
{
SourceHash
:
source
.
SourceHash
(),
From
:
*
fuzzedDepositInfo
.
FromAddr
,
To
:
fuzzedDepositInfo
.
ToAddr
,
Value
:
fuzzedDepositInfo
.
Value
,
Gas
:
fuzzedDepositInfo
.
Gas
,
Data
:
fuzzedDepositInfo
.
Data
,
Mint
:
fuzzedDepositInfo
.
Mint
,
IsSystemTransaction
:
false
,
}
// Marshal our actual log event
ev
=
MarshalDepositLogEvent
(
depositContractAddr
,
dep
)
// If we have a good version and our tx succeeded, we add this to our list of expected deposits to
// return.
if
status
==
types
.
ReceiptStatusSuccessful
{
expectedDeposits
=
append
(
expectedDeposits
,
dep
)
}
}
else
{
// If we're generated an unrelated log event (not deposit), fuzz some random parameters to use.
var
randomUnrelatedLogInfo
struct
{
Addr
*
common
.
Address
Topics
[]
common
.
Hash
Data
[]
byte
}
typeProvider
.
Fuzz
(
&
randomUnrelatedLogInfo
)
// Generate the random log
ev
=
testutils
.
GenerateLog
(
*
randomUnrelatedLogInfo
.
Addr
,
randomUnrelatedLogInfo
.
Topics
,
randomUnrelatedLogInfo
.
Data
)
}
ev
.
TxIndex
=
uint
(
i
)
ev
.
Index
=
logIndex
ev
.
BlockHash
=
blockHash
logs
=
append
(
logs
,
ev
)
logIndex
++
}
// Add our receipt to our list
receipts
=
append
(
receipts
,
&
types
.
Receipt
{
Type
:
types
.
DynamicFeeTxType
,
Status
:
status
,
Logs
:
logs
,
BlockHash
:
blockHash
,
TransactionIndex
:
uint
(
i
),
})
}
return
}
// FuzzDeriveDepositsRoundTrip tests the derivation of deposits from transaction receipt event logs. It mixes
// valid and invalid deposit transactions and ensures all valid deposits are derived as expected.
// This is a fuzz test corresponding to TestDeriveUserDeposits.
func
FuzzDeriveDepositsRoundTrip
(
f
*
testing
.
F
)
{
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
fuzzedData
[]
byte
)
{
// Create our fuzzer wrapper to generate complex values
typeProvider
:=
fuzz
.
NewFromGoFuzz
(
fuzzedData
)
.
NilChance
(
0
)
.
MaxDepth
(
10000
)
.
NumElements
(
0
,
0x100
)
.
Funcs
(
func
(
e
*
big
.
Int
,
c
fuzz
.
Continue
)
{
var
temp
[
32
]
byte
c
.
Fuzz
(
&
temp
)
e
.
SetBytes
(
temp
[
:
])
},
func
(
e
*
common
.
Hash
,
c
fuzz
.
Continue
)
{
var
temp
[
32
]
byte
c
.
Fuzz
(
&
temp
)
e
.
SetBytes
(
temp
[
:
])
},
func
(
e
*
common
.
Address
,
c
fuzz
.
Continue
)
{
var
temp
[
20
]
byte
c
.
Fuzz
(
&
temp
)
e
.
SetBytes
(
temp
[
:
])
})
// Create a dummy block hash for this block
var
blockHash
common
.
Hash
typeProvider
.
Fuzz
(
&
blockHash
)
// Fuzz to generate some random deposit events
receipts
,
expectedDeposits
:=
fuzzReceipts
(
typeProvider
,
blockHash
,
MockDepositContractAddr
)
// Derive our user deposits from the transaction receipts
derivedDeposits
,
err
:=
UserDeposits
(
receipts
,
MockDepositContractAddr
)
require
.
NoError
(
t
,
err
)
// Ensure all deposits we derived matched what we expected to receive.
require
.
Equal
(
t
,
len
(
derivedDeposits
),
len
(
expectedDeposits
))
for
i
,
derivedDeposit
:=
range
derivedDeposits
{
expectedDeposit
:=
expectedDeposits
[
i
]
require
.
Equal
(
t
,
expectedDeposit
,
derivedDeposit
)
}
})
}
// FuzzDeriveDepositsBadVersion ensures that if a deposit transaction receipt event log specifies an invalid deposit
// version, no deposits should be derived.
func
FuzzDeriveDepositsBadVersion
(
f
*
testing
.
F
)
{
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
fuzzedData
[]
byte
)
{
// Create our fuzzer wrapper to generate complex values
typeProvider
:=
fuzz
.
NewFromGoFuzz
(
fuzzedData
)
.
NilChance
(
0
)
.
MaxDepth
(
10000
)
.
NumElements
(
0
,
0x100
)
fuzzerutils
.
AddFuzzerFunctions
(
typeProvider
)
// Create a dummy block hash for this block
var
blockHash
common
.
Hash
typeProvider
.
Fuzz
(
&
blockHash
)
// Fuzz to generate some random deposit events
receipts
,
_
:=
fuzzReceipts
(
typeProvider
,
blockHash
,
MockDepositContractAddr
)
// Loop through all receipt logs and let the fuzzer determine which (if any) to patch.
hasBadDepositVersion
:=
false
for
_
,
receipt
:=
range
receipts
{
// TODO: Using a hardcoded index (Topics[3]) here is not ideal. The MarshalDepositLogEvent method should
// be spliced apart to be more configurable for these tests.
// Loop for each log in this receipt and check if it has a deposit event from our contract
for
_
,
log
:=
range
receipt
.
Logs
{
if
log
.
Address
==
MockDepositContractAddr
&&
len
(
log
.
Topics
)
>=
4
&&
log
.
Topics
[
0
]
==
DepositEventABIHash
{
// Determine if we should set a bad deposit version for this log
var
patchBadDeposit
bool
typeProvider
.
Fuzz
(
&
patchBadDeposit
)
if
patchBadDeposit
{
// Generate any topic but the deposit event versions we support.
// TODO: As opposed to keeping this hardcoded, a method such as IsValidVersion(v) should be
// used here.
badTopic
:=
DepositEventVersion0
for
badTopic
==
DepositEventVersion0
{
typeProvider
.
Fuzz
(
&
badTopic
)
}
// Set our bad topic and update our state
log
.
Topics
[
3
]
=
badTopic
hasBadDepositVersion
=
true
}
}
}
}
// Derive our user deposits from the transaction receipts
_
,
err
:=
UserDeposits
(
receipts
,
MockDepositContractAddr
)
// If we patched a bad deposit version this iteration, we should expect an error and not be able to proceed
// further
if
hasBadDepositVersion
{
require
.
Errorf
(
t
,
err
,
""
)
return
}
require
.
NoError
(
t
,
err
,
""
)
})
}
op-node/rollup/derive/l1_block_info_tob_test.go
0 → 100644
View file @
63072ca1
package
derive
import
(
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum-optimism/optimism/op-node/testutils/fuzzerutils"
fuzz
"github.com/google/gofuzz"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"math/big"
"math/rand"
"testing"
)
// FuzzParseL1InfoDepositTxDataValid is a fuzz test built from TestParseL1InfoDepositTxData, which constructs random
// L1 deposit tx info and derives a tx from it, then derives the info back from the tx, to ensure round-trip
// derivation is upheld. This generates "valid" data and ensures it is always derived back to original values.
func
FuzzParseL1InfoDepositTxDataValid
(
f
*
testing
.
F
)
{
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
fuzzedData
[]
byte
,
rngSeed
int64
)
{
// Create our fuzzer wrapper to generate complex values
typeProvider
:=
fuzz
.
NewFromGoFuzz
(
fuzzedData
)
.
NilChance
(
0
)
.
MaxDepth
(
10000
)
.
NumElements
(
0
,
0x100
)
fuzzerutils
.
AddFuzzerFunctions
(
typeProvider
)
// Generate our fuzzed value types to construct our L1 info
var
fuzzVars
struct
{
InfoBaseFee
*
big
.
Int
InfoTime
uint64
InfoNum
uint64
InfoSequenceNumber
uint64
}
typeProvider
.
Fuzz
(
&
fuzzVars
)
// Create an rng provider and construct an L1 info from random + fuzzed data.
rng
:=
rand
.
New
(
rand
.
NewSource
(
rngSeed
))
l1Info
:=
testutils
.
MakeL1Info
(
func
(
l
*
testutils
.
MockL1Info
)
{
l
.
InfoBaseFee
=
fuzzVars
.
InfoBaseFee
l
.
InfoTime
=
fuzzVars
.
InfoTime
l
.
InfoNum
=
fuzzVars
.
InfoNum
l
.
InfoSequenceNumber
=
fuzzVars
.
InfoSequenceNumber
})(
rng
)
// Create our deposit tx from our info
depTx
,
err
:=
L1InfoDeposit
(
l1Info
.
SequenceNumber
(),
l1Info
)
require
.
NoError
(
t
,
err
)
// Get our info from out deposit tx
res
,
err
:=
L1InfoDepositTxData
(
depTx
.
Data
)
require
.
NoError
(
t
,
err
,
"expected valid deposit info"
)
// Verify all parameters match in our round trip deriving operations
assert
.
Equal
(
t
,
res
.
Number
,
l1Info
.
NumberU64
())
assert
.
Equal
(
t
,
res
.
Time
,
l1Info
.
Time
())
assert
.
True
(
t
,
res
.
BaseFee
.
Sign
()
>=
0
)
assert
.
Equal
(
t
,
res
.
BaseFee
.
Bytes
(),
l1Info
.
BaseFee
()
.
Bytes
())
assert
.
Equal
(
t
,
res
.
BlockHash
,
l1Info
.
Hash
())
})
}
// FuzzParseL1InfoDepositTxDataBadLength is a fuzz test built from TestParseL1InfoDepositTxData, which constructs
// random L1 deposit tx info and derives a tx from it, then derives the info back from the tx, to ensure round-trip
// derivation is upheld. This generates "invalid" data and ensures it always throws an error where expected.
func
FuzzParseL1InfoDepositTxDataBadLength
(
f
*
testing
.
F
)
{
const
expectedDepositTxDataLength
=
4
+
32
+
32
+
32
+
32
+
32
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
fuzzedData
[]
byte
)
{
// Derive a transaction from random fuzzed data
_
,
err
:=
L1InfoDepositTxData
(
fuzzedData
)
// If the data is null, or too short or too long, we expect an error
if
fuzzedData
==
nil
||
len
(
fuzzedData
)
!=
expectedDepositTxDataLength
{
assert
.
Error
(
t
,
err
)
}
})
}
op-node/rollup/driver/state_tob_test.go
0 → 100644
View file @
63072ca1
package
driver
import
(
"context"
"errors"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/metrics"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert"
"math/rand"
"testing"
)
type
TestDummyOutputImpl
struct
{
willError
bool
outputInterface
}
func
(
d
TestDummyOutputImpl
)
createNewBlock
(
ctx
context
.
Context
,
l2Head
eth
.
L2BlockRef
,
l2SafeHead
eth
.
BlockID
,
l2Finalized
eth
.
BlockID
,
l1Origin
eth
.
L1BlockRef
)
(
eth
.
L2BlockRef
,
*
eth
.
ExecutionPayload
,
error
)
{
// If we're meant to error, return one
if
d
.
willError
{
return
l2Head
,
nil
,
errors
.
New
(
"the TestDummyOutputImpl.createNewBlock operation failed"
)
}
payload
:=
eth
.
ExecutionPayload
{
ParentHash
:
common
.
Hash
{},
FeeRecipient
:
common
.
Address
{},
StateRoot
:
eth
.
Bytes32
{},
ReceiptsRoot
:
eth
.
Bytes32
{},
LogsBloom
:
eth
.
Bytes256
{},
PrevRandao
:
eth
.
Bytes32
{},
BlockNumber
:
0
,
GasLimit
:
0
,
GasUsed
:
0
,
Timestamp
:
0
,
ExtraData
:
nil
,
BaseFeePerGas
:
eth
.
Uint256Quantity
{},
BlockHash
:
common
.
Hash
{},
Transactions
:
[]
eth
.
Data
{},
}
return
l2Head
,
&
payload
,
nil
}
type
TestDummyDerivationPipeline
struct
{
DerivationPipeline
}
func
(
d
TestDummyDerivationPipeline
)
Reset
()
{}
func
(
d
TestDummyDerivationPipeline
)
Step
(
ctx
context
.
Context
)
error
{
return
nil
}
func
(
d
TestDummyDerivationPipeline
)
SetUnsafeHead
(
head
eth
.
L2BlockRef
)
{}
func
(
d
TestDummyDerivationPipeline
)
AddUnsafePayload
(
payload
*
eth
.
ExecutionPayload
)
{}
func
(
d
TestDummyDerivationPipeline
)
Finalized
()
eth
.
L2BlockRef
{
return
eth
.
L2BlockRef
{}
}
func
(
d
TestDummyDerivationPipeline
)
SafeL2Head
()
eth
.
L2BlockRef
{
return
eth
.
L2BlockRef
{}
}
func
(
d
TestDummyDerivationPipeline
)
UnsafeL2Head
()
eth
.
L2BlockRef
{
return
eth
.
L2BlockRef
{}
}
func
(
d
TestDummyDerivationPipeline
)
Progress
()
derive
.
Progress
{
return
derive
.
Progress
{
Origin
:
eth
.
L1BlockRef
{},
Closed
:
false
,
}
}
// TestRejectCreateBlockBadTimestamp tests that a block creation with invalid timestamps will be caught.
// This does not test:
// - The findL1Origin call (it is hardcoded to be the head)
// - The outputInterface used to create a new block from a given payload.
// - The DerivationPipeline setting unsafe head (a mock provider is used to pretend to set it)
// - Metrics (only mocked enough to let the method proceed)
// - Publishing (network is set to nil so publishing won't occur)
func
TestRejectCreateBlockBadTimestamp
(
t
*
testing
.
T
)
{
// Create our random provider
rng
:=
rand
.
New
(
rand
.
NewSource
(
rand
.
Int63
()))
// Create our context for methods to execute under
ctx
:=
context
.
Background
()
// Create our fake L1/L2 heads and link them accordingly
l1HeadRef
:=
testutils
.
RandomBlockRef
(
rng
)
l2HeadRef
:=
testutils
.
RandomL2BlockRef
(
rng
)
l2l1OriginBlock
:=
l1HeadRef
l2HeadRef
.
L1Origin
=
l2l1OriginBlock
.
ID
()
// Create a rollup config
cfg
:=
rollup
.
Config
{
BlockTime
:
uint64
(
60
),
Genesis
:
rollup
.
Genesis
{
L1
:
l1HeadRef
.
ID
(),
L2
:
l2HeadRef
.
ID
(),
L2Time
:
0x7000
,
// dummy value
},
}
// Patch our timestamp so we fail
l2HeadRef
.
Time
=
l2l1OriginBlock
.
Time
-
(
cfg
.
BlockTime
*
2
)
// Create our outputter
outputProvider
:=
TestDummyOutputImpl
{
willError
:
false
}
// Create our state
s
:=
state
{
l1Head
:
l1HeadRef
,
l2Head
:
l2HeadRef
,
l2SafeHead
:
l2HeadRef
,
l2Finalized
:
l2HeadRef
,
Config
:
&
cfg
,
log
:
log
.
New
(),
output
:
outputProvider
,
derivation
:
TestDummyDerivationPipeline
{},
metrics
:
&
metrics
.
Metrics
{
TransactionsSequencedTotal
:
prometheus
.
NewCounter
(
prometheus
.
CounterOpts
{})},
}
// Create a new block
// - L2Head's L1Origin, its timestamp should be greater than L1 genesis.
// - L2Head timestamp + BlockTime should be greater than or equal to the L1 Time.
err
:=
s
.
createNewL2Block
(
ctx
)
// Verify the L1Origin's timestamp is greater than L1 genesis in our config.
if
l2l1OriginBlock
.
Number
<
s
.
Config
.
Genesis
.
L1
.
Number
{
assert
.
Nil
(
t
,
err
)
return
}
// Verify the new L2 block to create will have a time stamp equal or newer than our L1 origin block we derive from.
if
l2HeadRef
.
Time
+
cfg
.
BlockTime
<
l2l1OriginBlock
.
Time
{
// If not, we expect a specific error.
// TODO: This isn't the cleanest, we should construct + compare the whole error message.
assert
.
NotNil
(
t
,
err
)
assert
.
Contains
(
t
,
err
.
Error
(),
"cannot build L2 block on top"
)
assert
.
Contains
(
t
,
err
.
Error
(),
"for time"
)
assert
.
Contains
(
t
,
err
.
Error
(),
"before L1 origin"
)
return
}
// Otherwise we should have no error.
assert
.
Nil
(
t
,
err
)
// If we expected the outputter to error, capture that here
if
outputProvider
.
willError
{
assert
.
NotNil
(
t
,
err
,
"outputInterface failed to createNewBlock, so createNewL2Block should also have failed"
)
return
}
// Otherwise we should have no error.
assert
.
Nil
(
t
,
err
)
}
// FuzzRejectCreateBlockBadTimestamp is a property test derived from the TestRejectCreateBlockBadTimestamp unit test.
// It fuzzes timestamps and block times to find a configuration to violate error checking.
func
FuzzRejectCreateBlockBadTimestamp
(
f
*
testing
.
F
)
{
f
.
Fuzz
(
func
(
t
*
testing
.
T
,
randSeed
int64
,
l2Time
uint64
,
blockTime
uint64
,
forceOutputFail
bool
,
currentL2HeadTime
uint64
)
{
// Create our random provider
rng
:=
rand
.
New
(
rand
.
NewSource
(
randSeed
))
// Create our context for methods to execute under
ctx
:=
context
.
Background
()
// Create our fake L1/L2 heads and link them accordingly
l1HeadRef
:=
testutils
.
RandomBlockRef
(
rng
)
l2HeadRef
:=
testutils
.
RandomL2BlockRef
(
rng
)
l2l1OriginBlock
:=
l1HeadRef
l2HeadRef
.
L1Origin
=
l2l1OriginBlock
.
ID
()
// TODO: Cap our block time so it doesn't overflow
if
blockTime
>
0x100000
{
blockTime
=
0x100000
}
// Create a rollup config
cfg
:=
rollup
.
Config
{
BlockTime
:
blockTime
,
Genesis
:
rollup
.
Genesis
{
L1
:
l1HeadRef
.
ID
(),
L2
:
l2HeadRef
.
ID
(),
L2Time
:
l2Time
,
// dummy value
},
}
// Patch our timestamp so we fail
l2HeadRef
.
Time
=
currentL2HeadTime
// Create our outputter
outputProvider
:=
TestDummyOutputImpl
{
willError
:
forceOutputFail
}
// Create our state
s
:=
state
{
l1Head
:
l1HeadRef
,
l2Head
:
l2HeadRef
,
l2SafeHead
:
l2HeadRef
,
l2Finalized
:
l2HeadRef
,
Config
:
&
cfg
,
log
:
log
.
New
(),
output
:
outputProvider
,
derivation
:
TestDummyDerivationPipeline
{},
metrics
:
&
metrics
.
Metrics
{
TransactionsSequencedTotal
:
prometheus
.
NewCounter
(
prometheus
.
CounterOpts
{})},
}
// Create a new block
// - L2Head's L1Origin, its timestamp should be greater than L1 genesis.
// - L2Head timestamp + BlockTime should be greater than or equal to the L1 Time.
err
:=
s
.
createNewL2Block
(
ctx
)
// Verify the L1Origin's timestamp is greater than L1 genesis in our config.
if
l2l1OriginBlock
.
Number
<
s
.
Config
.
Genesis
.
L1
.
Number
{
assert
.
Nil
(
t
,
err
)
return
}
// Verify the new L2 block to create will have a time stamp equal or newer than our L1 origin block we derive from.
if
l2HeadRef
.
Time
+
cfg
.
BlockTime
<
l2l1OriginBlock
.
Time
{
// If not, we expect a specific error.
// TODO: This isn't the cleanest, we should construct + compare the whole error message.
assert
.
NotNil
(
t
,
err
)
assert
.
Contains
(
t
,
err
.
Error
(),
"cannot build L2 block on top"
)
assert
.
Contains
(
t
,
err
.
Error
(),
"for time"
)
assert
.
Contains
(
t
,
err
.
Error
(),
"before L1 origin"
)
return
}
// Otherwise we should have no error.
assert
.
Nil
(
t
,
err
)
// If we expected the outputter to error, capture that here
if
outputProvider
.
willError
{
assert
.
NotNil
(
t
,
err
,
"outputInterface failed to createNewBlock, so createNewL2Block should also have failed"
)
return
}
// Otherwise we should have no error.
assert
.
Nil
(
t
,
err
)
})
}
op-node/testutils/fuzzerutils/fuzzer_functions.go
0 → 100644
View file @
63072ca1
package
fuzzerutils
import
(
"math/big"
"github.com/ethereum/go-ethereum/common"
fuzz
"github.com/google/gofuzz"
)
// AddFuzzerFunctions takes a fuzz.Fuzzer and adds a list of functions to handle different
// data types in a fuzzing campaign. It adds support for commonly used types throughout the
// application.
func
AddFuzzerFunctions
(
fuzzer
*
fuzz
.
Fuzzer
)
{
fuzzer
.
Funcs
(
func
(
e
*
big
.
Int
,
c
fuzz
.
Continue
)
{
var
temp
[
32
]
byte
c
.
Fuzz
(
&
temp
)
e
.
SetBytes
(
temp
[
:
])
},
func
(
e
*
common
.
Hash
,
c
fuzz
.
Continue
)
{
var
temp
[
32
]
byte
c
.
Fuzz
(
&
temp
)
e
.
SetBytes
(
temp
[
:
])
},
func
(
e
*
common
.
Address
,
c
fuzz
.
Continue
)
{
var
temp
[
20
]
byte
c
.
Fuzz
(
&
temp
)
e
.
SetBytes
(
temp
[
:
])
},
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment