Commit 54f85667 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into refcell/remove-eof-crawler

parents 08833f84 0bbd440c
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
"CrossDomainMessenger", "CrossDomainMessenger",
"MIPS", "MIPS",
"PreimageOracle", "PreimageOracle",
"BlockOracle",
"EAS", "EAS",
"SchemaRegistry" "SchemaRegistry"
] ]
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Code generated - DO NOT EDIT.
// This file is a generated binding and any manual changes will be lost.
package bindings
import (
"encoding/json"
"github.com/ethereum-optimism/optimism/op-bindings/solc"
)
const BlockOracleStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"src/dispute/BlockOracle.sol:BlockOracle\",\"label\":\"blocks\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_uint256,t_struct(BlockInfo)1001_storage)\"}],\"types\":{\"t_mapping(t_uint256,t_struct(BlockInfo)1001_storage)\":{\"encoding\":\"mapping\",\"label\":\"mapping(uint256 =\u003e struct BlockOracle.BlockInfo)\",\"numberOfBytes\":\"32\",\"key\":\"t_uint256\",\"value\":\"t_struct(BlockInfo)1001_storage\"},\"t_struct(BlockInfo)1001_storage\":{\"encoding\":\"inplace\",\"label\":\"struct BlockOracle.BlockInfo\",\"numberOfBytes\":\"64\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_userDefinedValueType(Hash)1002\":{\"encoding\":\"inplace\",\"label\":\"Hash\",\"numberOfBytes\":\"32\"},\"t_userDefinedValueType(Timestamp)1003\":{\"encoding\":\"inplace\",\"label\":\"Timestamp\",\"numberOfBytes\":\"8\"}}}"
var BlockOracleStorageLayout = new(solc.StorageLayout)
var BlockOracleDeployedBin = "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806399d548aa1461003b578063c2c4c5c114610078575b600080fd5b61004e6100493660046101b8565b61008e565b604080518251815260209283015167ffffffffffffffff1692810192909252015b60405180910390f35b61008061010d565b60405190815260200161006f565b604080518082018252600080825260209182018190528381528082528281208351808501909452805480855260019091015467ffffffffffffffff169284019290925203610108576040517f37cf270500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b919050565b600061011a6001436101d1565b60408051808201825282408082524267ffffffffffffffff81811660208086018281526000898152918290528782209651875551600190960180547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016969093169590951790915593519495509093909291849186917fb67ff58b33060fd371a35ae2d9f1c3cdaec9b8197969f6efe2594a1ff4ba68c691a4505090565b6000602082840312156101ca57600080fd5b5035919050565b60008282101561020a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b50039056fea164736f6c634300080f000a"
func init() {
if err := json.Unmarshal([]byte(BlockOracleStorageLayoutJSON), BlockOracleStorageLayout); err != nil {
panic(err)
}
layouts["BlockOracle"] = BlockOracleStorageLayout
deployedBytecodes["BlockOracle"] = BlockOracleDeployedBin
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -27,6 +27,12 @@ func setupFaultDisputeGame() (common.Address, *bind.TransactOpts, *backends.Simu ...@@ -27,6 +27,12 @@ func setupFaultDisputeGame() (common.Address, *bind.TransactOpts, *backends.Simu
return common.Address{}, nil, nil, nil, err return common.Address{}, nil, nil, nil, err
} }
backend := backends.NewSimulatedBackend(core.GenesisAlloc{from: {Balance: big.NewInt(params.Ether)}}, 50_000_000) backend := backends.NewSimulatedBackend(core.GenesisAlloc{from: {Balance: big.NewInt(params.Ether)}}, 50_000_000)
blockHashOracle, _, _, err := bindings.DeployBlockOracle(opts, backend)
if err != nil {
return common.Address{}, nil, nil, nil, err
}
_, _, contract, err := bindings.DeployFaultDisputeGame( _, _, contract, err := bindings.DeployFaultDisputeGame(
opts, opts,
backend, backend,
...@@ -35,6 +41,7 @@ func setupFaultDisputeGame() (common.Address, *bind.TransactOpts, *backends.Simu ...@@ -35,6 +41,7 @@ func setupFaultDisputeGame() (common.Address, *bind.TransactOpts, *backends.Simu
uint64(604800), // 7 days uint64(604800), // 7 days
common.Address{0xdd}, // VM common.Address{0xdd}, // VM
common.Address{0xee}, // L2OutputOracle (Not used in Alphabet Game) common.Address{0xee}, // L2OutputOracle (Not used in Alphabet Game)
blockHashOracle, // Block hash oracle
) )
if err != nil { if err != nil {
return common.Address{}, nil, nil, nil, err return common.Address{}, nil, nil, nil, err
......
...@@ -7,9 +7,11 @@ import ( ...@@ -7,9 +7,11 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer" "github.com/ethereum-optimism/optimism/op-chain-ops/deployer"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-service/client/utils" "github.com/ethereum-optimism/optimism/op-service/client/utils"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
...@@ -18,7 +20,7 @@ import ( ...@@ -18,7 +20,7 @@ import (
// It configures the alphabet fault game as game type 0 (faultGameType) // It configures the alphabet fault game as game type 0 (faultGameType)
// If/when the dispute game factory becomes a predeployed contract this can be removed and just use the // If/when the dispute game factory becomes a predeployed contract this can be removed and just use the
// predeployed version // predeployed version
func deployDisputeGameContracts(require *require.Assertions, ctx context.Context, client *ethclient.Client, opts *bind.TransactOpts, gameDuration uint64) *bindings.DisputeGameFactory { func deployDisputeGameContracts(require *require.Assertions, ctx context.Context, clock *clock.AdvancingClock, client *ethclient.Client, opts *bind.TransactOpts, gameDuration uint64) (*bindings.DisputeGameFactory, *big.Int) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Minute) ctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
defer cancel() defer cancel()
// Deploy the proxy // Deploy the proxy
...@@ -38,7 +40,9 @@ func deployDisputeGameContracts(require *require.Assertions, ctx context.Context ...@@ -38,7 +40,9 @@ func deployDisputeGameContracts(require *require.Assertions, ctx context.Context
require.NoError(err) require.NoError(err)
data, err := disputeGameFactoryAbi.Pack("initialize", deployer.TestAddress) data, err := disputeGameFactoryAbi.Pack("initialize", deployer.TestAddress)
require.NoError(err) require.NoError(err)
_, err = proxy.UpgradeToAndCall(opts, factoryAddr, data) tx, err = proxy.UpgradeToAndCall(opts, factoryAddr, data)
require.NoError(err)
_, err = utils.WaitReceiptOK(ctx, client, tx.Hash())
require.NoError(err) require.NoError(err)
factory, err := bindings.NewDisputeGameFactory(proxyAddr, client) factory, err := bindings.NewDisputeGameFactory(proxyAddr, client)
require.NoError(err) require.NoError(err)
...@@ -50,18 +54,67 @@ func deployDisputeGameContracts(require *require.Assertions, ctx context.Context ...@@ -50,18 +54,67 @@ func deployDisputeGameContracts(require *require.Assertions, ctx context.Context
alphaVMAddr, err := bind.WaitDeployed(ctx, client, tx) alphaVMAddr, err := bind.WaitDeployed(ctx, client, tx)
require.NoError(err) require.NoError(err)
l2OutputOracle, err := bindings.NewL2OutputOracle(config.L1Deployments.L2OutputOracleProxy, client)
require.NoError(err)
// Deploy the block hash oracle
_, tx, _, err = bindings.DeployBlockOracle(opts, client)
require.NoError(err)
blockHashOracleAddr, err := bind.WaitDeployed(ctx, client, tx)
require.NoError(err)
blockHashOracle, err := bindings.NewBlockOracle(blockHashOracleAddr, client)
require.NoError(err)
// Deploy the fault dispute game implementation // Deploy the fault dispute game implementation
_, tx, _, err = bindings.DeployFaultDisputeGame(opts, client, alphabetVMAbsolutePrestateClaim, big.NewInt(alphabetGameDepth), gameDuration, alphaVMAddr, common.Address{0xBE, 0xEF}) _, tx, _, err = bindings.DeployFaultDisputeGame(
opts,
client,
alphabetVMAbsolutePrestateClaim,
big.NewInt(alphabetGameDepth),
gameDuration,
alphaVMAddr,
config.L1Deployments.L2OutputOracleProxy,
blockHashOracleAddr,
)
require.NoError(err) require.NoError(err)
faultDisputeGameAddr, err := bind.WaitDeployed(ctx, client, tx) faultDisputeGameAddr, err := bind.WaitDeployed(ctx, client, tx)
require.NoError(err) require.NoError(err)
// Create a proposer transactor
secrets, err := e2eutils.DefaultMnemonicConfig.Secrets()
require.NoError(err)
chainId, err := client.ChainID(ctx)
require.NoError(err)
proposerOpts, err := bind.NewKeyedTransactorWithChainID(secrets.Proposer, chainId)
require.NoError(err)
// Propose 2 outputs
for i := uint8(0); i < 2; i++ {
nextBlockNumber, err := l2OutputOracle.NextBlockNumber(&bind.CallOpts{Pending: true, Context: ctx})
require.NoError(err)
block, err := client.BlockByNumber(ctx, big.NewInt(int64(i)))
require.NoError(err)
tx, err = l2OutputOracle.ProposeL2Output(proposerOpts, [32]byte{i + 1}, nextBlockNumber, block.Hash(), block.Number())
require.NoError(err)
_, err = utils.WaitReceiptOK(ctx, client, tx.Hash())
require.NoError(err)
}
// Set the fault game type implementation // Set the fault game type implementation
tx, err = factory.SetImplementation(opts, faultGameType, faultDisputeGameAddr) tx, err = factory.SetImplementation(opts, faultGameType, faultDisputeGameAddr)
require.NoError(err) require.NoError(err)
_, err = utils.WaitReceiptOK(ctx, client, tx.Hash()) _, err = utils.WaitReceiptOK(ctx, client, tx.Hash())
require.NoError(err, "wait for final transaction to be included and OK") require.NoError(err, "wait for final transaction to be included and OK")
return factory // Warp 15 seconds ahead for a diff in the timestamp.
clock.AdvanceTime(15 * time.Second)
// Store the current block in the oracle
tx, err = blockHashOracle.Checkpoint(opts)
require.NoError(err)
r, err := utils.WaitReceiptOK(ctx, client, tx.Hash())
require.NoError(err, "failed to store block in blockoracle")
return factory, new(big.Int).Sub(r.BlockNumber, big.NewInt(1))
} }
...@@ -2,6 +2,7 @@ package disputegame ...@@ -2,6 +2,7 @@ package disputegame
import ( import (
"context" "context"
"encoding/binary"
"fmt" "fmt"
"math/big" "math/big"
"testing" "testing"
...@@ -14,6 +15,7 @@ import ( ...@@ -14,6 +15,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-service/client/utils" "github.com/ethereum-optimism/optimism/op-service/client/utils"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
...@@ -33,7 +35,6 @@ const ( ...@@ -33,7 +35,6 @@ const (
StatusDefenderWins StatusDefenderWins
) )
var alphaExtraData = common.Hex2Bytes("1000000000000000000000000000000000000000000000000000000000000000")
var alphabetVMAbsolutePrestate = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000060") var alphabetVMAbsolutePrestate = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000060")
var alphabetVMAbsolutePrestateClaim = crypto.Keccak256Hash(alphabetVMAbsolutePrestate) var alphabetVMAbsolutePrestateClaim = crypto.Keccak256Hash(alphabetVMAbsolutePrestate)
var CorrectAlphabet = "abcdefghijklmnop" var CorrectAlphabet = "abcdefghijklmnop"
...@@ -44,16 +45,17 @@ type FactoryHelper struct { ...@@ -44,16 +45,17 @@ type FactoryHelper struct {
client *ethclient.Client client *ethclient.Client
opts *bind.TransactOpts opts *bind.TransactOpts
factory *bindings.DisputeGameFactory factory *bindings.DisputeGameFactory
l1Head *big.Int
} }
func NewFactoryHelper(t *testing.T, ctx context.Context, client *ethclient.Client, gameDuration uint64) *FactoryHelper { func NewFactoryHelper(t *testing.T, ctx context.Context, clock *clock.AdvancingClock, client *ethclient.Client, gameDuration uint64) *FactoryHelper {
require := require.New(t) require := require.New(t)
chainID, err := client.ChainID(ctx) chainID, err := client.ChainID(ctx)
require.NoError(err) require.NoError(err)
opts, err := bind.NewKeyedTransactorWithChainID(deployer.TestKey, chainID) opts, err := bind.NewKeyedTransactorWithChainID(deployer.TestKey, chainID)
require.NoError(err) require.NoError(err)
factory := deployDisputeGameContracts(require, ctx, client, opts, gameDuration) factory, l1Head := deployDisputeGameContracts(require, ctx, clock, client, opts, gameDuration)
return &FactoryHelper{ return &FactoryHelper{
t: t, t: t,
...@@ -61,6 +63,7 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, client *ethclient.Clien ...@@ -61,6 +63,7 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, client *ethclient.Clien
client: client, client: client,
opts: opts, opts: opts,
factory: factory, factory: factory,
l1Head: l1Head,
} }
} }
...@@ -70,7 +73,10 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s ...@@ -70,7 +73,10 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s
trace := alphabet.NewTraceProvider(claimedAlphabet, 4) trace := alphabet.NewTraceProvider(claimedAlphabet, 4)
rootClaim, err := trace.Get(ctx, lastAlphabetTraceIndex) rootClaim, err := trace.Get(ctx, lastAlphabetTraceIndex)
h.require.NoError(err, "get root claim") h.require.NoError(err, "get root claim")
tx, err := h.factory.Create(h.opts, faultGameType, rootClaim, alphaExtraData) extraData := make([]byte, 64)
binary.BigEndian.PutUint64(extraData[24:], uint64(8))
binary.BigEndian.PutUint64(extraData[56:], h.l1Head.Uint64())
tx, err := h.factory.Create(h.opts, faultGameType, rootClaim, extraData)
h.require.NoError(err, "create fault dispute game") h.require.NoError(err, "create fault dispute game")
rcpt, err := utils.WaitReceiptOK(ctx, h.client, tx.Hash()) rcpt, err := utils.WaitReceiptOK(ctx, h.client, tx.Hash())
h.require.NoError(err, "wait for create fault dispute game receipt to be OK") h.require.NoError(err, "wait for create fault dispute game receipt to be OK")
......
...@@ -21,7 +21,7 @@ func TestResolveDisputeGame(t *testing.T) { ...@@ -21,7 +21,7 @@ func TestResolveDisputeGame(t *testing.T) {
t.Cleanup(sys.Close) t.Cleanup(sys.Close)
gameDuration := 24 * time.Hour gameDuration := 24 * time.Hour
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, l1Client, uint64(gameDuration.Seconds())) disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.TimeTravelClock, l1Client, uint64(gameDuration.Seconds()))
game := disputeGameFactory.StartAlphabetGame(ctx, "zyxwvut") game := disputeGameFactory.StartAlphabetGame(ctx, "zyxwvut")
require.NotNil(t, game) require.NotNil(t, game)
...@@ -119,7 +119,7 @@ func TestChallengerCompleteDisputeGame(t *testing.T) { ...@@ -119,7 +119,7 @@ func TestChallengerCompleteDisputeGame(t *testing.T) {
t.Cleanup(sys.Close) t.Cleanup(sys.Close)
gameDuration := 24 * time.Hour gameDuration := 24 * time.Hour
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, l1Client, uint64(gameDuration.Seconds())) disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.TimeTravelClock, l1Client, uint64(gameDuration.Seconds()))
game := disputeGameFactory.StartAlphabetGame(ctx, test.rootClaimAlphabet) game := disputeGameFactory.StartAlphabetGame(ctx, test.rootClaimAlphabet)
require.NotNil(t, game) require.NotNil(t, game)
......
...@@ -16,6 +16,8 @@ AssetReceiverTest:test_withdrawETHwithAmount_unauthorized_reverts() (gas: 10738) ...@@ -16,6 +16,8 @@ AssetReceiverTest:test_withdrawETHwithAmount_unauthorized_reverts() (gas: 10738)
AttestationStationTest:test_attest_bulk_succeeds() (gas: 703740) AttestationStationTest:test_attest_bulk_succeeds() (gas: 703740)
AttestationStationTest:test_attest_individual_succeeds() (gas: 632078) AttestationStationTest:test_attest_individual_succeeds() (gas: 632078)
AttestationStationTest:test_attest_single_succeeds() (gas: 651316) AttestationStationTest:test_attest_single_succeeds() (gas: 651316)
BlockOracle_Test:test_checkpointAndLoad_succeeds() (gas: 58341)
BlockOracle_Test:test_load_noBlockHash_reverts() (gas: 12805)
Bytes_slice_Test:test_slice_acrossMultipleWords_works() (gas: 9413) Bytes_slice_Test:test_slice_acrossMultipleWords_works() (gas: 9413)
Bytes_slice_Test:test_slice_acrossWords_works() (gas: 1430) Bytes_slice_Test:test_slice_acrossWords_works() (gas: 1430)
Bytes_slice_Test:test_slice_fromNonZeroIdx_works() (gas: 17240) Bytes_slice_Test:test_slice_fromNonZeroIdx_works() (gas: 17240)
...@@ -46,9 +48,9 @@ CrossDomainOwnable_Test:test_onlyOwner_succeeds() (gas: 34883) ...@@ -46,9 +48,9 @@ CrossDomainOwnable_Test:test_onlyOwner_succeeds() (gas: 34883)
DeleteOutput:test_script_succeeds() (gas: 3100) DeleteOutput:test_script_succeeds() (gas: 3100)
DeployerWhitelist_Test:test_owner_succeeds() (gas: 7582) DeployerWhitelist_Test:test_owner_succeeds() (gas: 7582)
DeployerWhitelist_Test:test_storageSlots_succeeds() (gas: 33395) DeployerWhitelist_Test:test_storageSlots_succeeds() (gas: 33395)
DisputeGameFactory_Owner_Test:test_owner_succeeds() (gas: 12559) DisputeGameFactory_Owner_Test:test_owner_succeeds() (gas: 12581)
DisputeGameFactory_SetImplementation_Test:test_setImplementation_notOwner_reverts() (gas: 16042) DisputeGameFactory_SetImplementation_Test:test_setImplementation_notOwner_reverts() (gas: 16042)
DisputeGameFactory_SetImplementation_Test:test_setImplementation_succeeds() (gas: 44243) DisputeGameFactory_SetImplementation_Test:test_setImplementation_succeeds() (gas: 44301)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_notOwner_reverts() (gas: 15950) DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_notOwner_reverts() (gas: 15950)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_succeeds() (gas: 18642) DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_succeeds() (gas: 18642)
Drippie_Test:test_create_calledTwice_reverts() (gas: 168931) Drippie_Test:test_create_calledTwice_reverts() (gas: 168931)
...@@ -85,36 +87,38 @@ FaucetTest:test_nonAdmin_drip_fails() (gas: 262520) ...@@ -85,36 +87,38 @@ FaucetTest:test_nonAdmin_drip_fails() (gas: 262520)
FaucetTest:test_receive_succeeds() (gas: 17401) FaucetTest:test_receive_succeeds() (gas: 17401)
FaucetTest:test_withdraw_nonAdmin_reverts() (gas: 13145) FaucetTest:test_withdraw_nonAdmin_reverts() (gas: 13145)
FaucetTest:test_withdraw_succeeds() (gas: 78359) FaucetTest:test_withdraw_succeeds() (gas: 78359)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 501957) FaultDisputeGame_ResolvesCorrectly_CorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 498844)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 508759) FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 505718)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 505478) FaultDisputeGame_ResolvesCorrectly_CorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 502387)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 508657) FaultDisputeGame_ResolvesCorrectly_CorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 505594)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 507974) FaultDisputeGame_ResolvesCorrectly_CorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 504883)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 500722) FaultDisputeGame_ResolvesCorrectly_IncorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 497609)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 507524) FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 504483)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 504243) FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 501152)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 505422) FaultDisputeGame_ResolvesCorrectly_IncorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 502359)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 504739) FaultDisputeGame_ResolvesCorrectly_IncorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 501648)
FaultDisputeGame_Test:test_extraData_succeeds() (gas: 17404) FaultDisputeGame_Test:test_extraData_succeeds() (gas: 32354)
FaultDisputeGame_Test:test_gameData_succeeds() (gas: 17939) FaultDisputeGame_Test:test_gameData_succeeds() (gas: 32806)
FaultDisputeGame_Test:test_gameStart_succeeds() (gas: 10315) FaultDisputeGame_Test:test_gameStart_succeeds() (gas: 10388)
FaultDisputeGame_Test:test_gameType_succeeds() (gas: 8260) FaultDisputeGame_Test:test_gameType_succeeds() (gas: 8266)
FaultDisputeGame_Test:test_initialRootClaimData_succeeds() (gas: 17624) FaultDisputeGame_Test:test_initialize_correctData_succeeds() (gas: 57716)
FaultDisputeGame_Test:test_move_clockCorrectness_succeeds() (gas: 419180) FaultDisputeGame_Test:test_initialize_firstOutput_reverts() (gas: 210532)
FaultDisputeGame_Test:test_move_clockTimeExceeded_reverts() (gas: 26421) FaultDisputeGame_Test:test_initialize_l1HeadTooOld_reverts() (gas: 228402)
FaultDisputeGame_Test:test_move_defendRoot_reverts() (gas: 13360) FaultDisputeGame_Test:test_move_clockCorrectness_succeeds() (gas: 415921)
FaultDisputeGame_Test:test_move_duplicateClaim_reverts() (gas: 104120) FaultDisputeGame_Test:test_move_clockTimeExceeded_reverts() (gas: 26428)
FaultDisputeGame_Test:test_move_gameDepthExceeded_reverts() (gas: 411546) FaultDisputeGame_Test:test_move_defendRoot_reverts() (gas: 13388)
FaultDisputeGame_Test:test_move_gameNotInProgress_reverts() (gas: 11012) FaultDisputeGame_Test:test_move_duplicateClaim_reverts() (gas: 103377)
FaultDisputeGame_Test:test_move_nonExistentParent_reverts() (gas: 24677) FaultDisputeGame_Test:test_move_gameDepthExceeded_reverts() (gas: 408294)
FaultDisputeGame_Test:test_move_simpleAttack_succeeds() (gas: 108110) FaultDisputeGame_Test:test_move_gameNotInProgress_reverts() (gas: 11024)
FaultDisputeGame_Test:test_resolve_challengeContested_succeeds() (gas: 226511) FaultDisputeGame_Test:test_move_nonExistentParent_reverts() (gas: 24689)
FaultDisputeGame_Test:test_resolve_notInProgress_reverts() (gas: 9657) FaultDisputeGame_Test:test_move_simpleAttack_succeeds() (gas: 107300)
FaultDisputeGame_Test:test_resolve_rootContested_succeeds() (gas: 110642) FaultDisputeGame_Test:test_resolve_challengeContested_succeeds() (gas: 224869)
FaultDisputeGame_Test:test_resolve_rootUncontestedClockNotExpired_succeeds() (gas: 21437) FaultDisputeGame_Test:test_resolve_notInProgress_reverts() (gas: 9664)
FaultDisputeGame_Test:test_resolve_rootUncontested_succeeds() (gas: 27288) FaultDisputeGame_Test:test_resolve_rootContested_succeeds() (gas: 109838)
FaultDisputeGame_Test:test_resolve_teamDeathmatch_succeeds() (gas: 398859) FaultDisputeGame_Test:test_resolve_rootUncontestedClockNotExpired_succeeds() (gas: 21443)
FaultDisputeGame_Test:test_rootClaim_succeeds() (gas: 8225) FaultDisputeGame_Test:test_resolve_rootUncontested_succeeds() (gas: 27278)
FaultDisputeGame_Test:test_resolve_teamDeathmatch_succeeds() (gas: 395607)
FaultDisputeGame_Test:test_rootClaim_succeeds() (gas: 8253)
FeeVault_Test:test_constructor_succeeds() (gas: 18185) FeeVault_Test:test_constructor_succeeds() (gas: 18185)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 352113) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 352113)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2950320) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2950320)
...@@ -552,11 +556,12 @@ SafeCall_Test:test_callWithMinGas_noLeakageHigh_succeeds() (gas: 1021670598) ...@@ -552,11 +556,12 @@ SafeCall_Test:test_callWithMinGas_noLeakageHigh_succeeds() (gas: 1021670598)
SafeCall_Test:test_callWithMinGas_noLeakageLow_succeeds() (gas: 1095190710) SafeCall_Test:test_callWithMinGas_noLeakageLow_succeeds() (gas: 1095190710)
Semver_Test:test_behindProxy_succeeds() (gas: 506748) Semver_Test:test_behindProxy_succeeds() (gas: 506748)
Semver_Test:test_version_succeeds() (gas: 9418) Semver_Test:test_version_succeeds() (gas: 9418)
SequencerFeeVault_L2Withdrawal_Test:test_withdraw_toL2_succeeds() (gas: 78286) SequencerFeeVault_L2Withdrawal_Test:test_withdraw_toL2_succeeds() (gas: 78333)
SequencerFeeVault_L2Withdrawal_Test:test_withdraw_toL2recipientReverts_fails() (gas: 46486)
SequencerFeeVault_Test:test_constructor_succeeds() (gas: 5526) SequencerFeeVault_Test:test_constructor_succeeds() (gas: 5526)
SequencerFeeVault_Test:test_minWithdrawalAmount_succeeds() (gas: 5464) SequencerFeeVault_Test:test_minWithdrawalAmount_succeeds() (gas: 5464)
SequencerFeeVault_Test:test_receive_succeeds() (gas: 17373) SequencerFeeVault_Test:test_receive_succeeds() (gas: 17373)
SequencerFeeVault_Test:test_withdraw_notEnough_reverts() (gas: 9331) SequencerFeeVault_Test:test_withdraw_notEnough_reverts() (gas: 9332)
SequencerFeeVault_Test:test_withdraw_toL1_succeeds() (gas: 169242) SequencerFeeVault_Test:test_withdraw_toL1_succeeds() (gas: 169242)
SetPrevBaseFee_Test:test_setPrevBaseFee_succeeds() (gas: 11515) SetPrevBaseFee_Test:test_setPrevBaseFee_succeeds() (gas: 11515)
StandardBridge_Stateless_Test:test_isCorrectTokenPair_succeeds() (gas: 49936) StandardBridge_Stateless_Test:test_isCorrectTokenPair_succeeds() (gas: 49936)
......
...@@ -9,30 +9,31 @@ import { stdJson } from "forge-std/StdJson.sol"; ...@@ -9,30 +9,31 @@ import { stdJson } from "forge-std/StdJson.sol";
import { Deployer } from "./Deployer.sol"; import { Deployer } from "./Deployer.sol";
import { DeployConfig } from "./DeployConfig.s.sol"; import { DeployConfig } from "./DeployConfig.s.sol";
import { ProxyAdmin } from "../src/universal/ProxyAdmin.sol"; import { ProxyAdmin } from "src/universal/ProxyAdmin.sol";
import { AddressManager } from "../src/legacy/AddressManager.sol"; import { AddressManager } from "src/legacy/AddressManager.sol";
import { Proxy } from "../src/universal/Proxy.sol"; import { Proxy } from "src/universal/Proxy.sol";
import { L1StandardBridge } from "../src/L1/L1StandardBridge.sol"; import { L1StandardBridge } from "src/L1/L1StandardBridge.sol";
import { OptimismPortal } from "../src/L1/OptimismPortal.sol"; import { OptimismPortal } from "src/L1/OptimismPortal.sol";
import { L1ChugSplashProxy } from "../src/legacy/L1ChugSplashProxy.sol"; import { L1ChugSplashProxy } from "src/legacy/L1ChugSplashProxy.sol";
import { ResolvedDelegateProxy } from "../src/legacy/ResolvedDelegateProxy.sol"; import { ResolvedDelegateProxy } from "src/legacy/ResolvedDelegateProxy.sol";
import { L1CrossDomainMessenger } from "../src/L1/L1CrossDomainMessenger.sol"; import { L1CrossDomainMessenger } from "src/L1/L1CrossDomainMessenger.sol";
import { L2OutputOracle } from "../src/L1/L2OutputOracle.sol"; import { L2OutputOracle } from "src/L1/L2OutputOracle.sol";
import { OptimismMintableERC20Factory } from "../src/universal/OptimismMintableERC20Factory.sol"; import { OptimismMintableERC20Factory } from "src/universal/OptimismMintableERC20Factory.sol";
import { SystemConfig } from "../src/L1/SystemConfig.sol"; import { SystemConfig } from "src/L1/SystemConfig.sol";
import { ResourceMetering } from "../src/L1/ResourceMetering.sol"; import { ResourceMetering } from "src/L1/ResourceMetering.sol";
import { Constants } from "../src/libraries/Constants.sol"; import { Constants } from "src/libraries/Constants.sol";
import { DisputeGameFactory } from "../src/dispute/DisputeGameFactory.sol"; import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { FaultDisputeGame } from "../src/dispute/FaultDisputeGame.sol"; import { FaultDisputeGame } from "src/dispute/FaultDisputeGame.sol";
import { PreimageOracle } from "../src/cannon/PreimageOracle.sol"; import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
import { MIPS } from "../src/cannon/MIPS.sol"; import { MIPS } from "src/cannon/MIPS.sol";
import { L1ERC721Bridge } from "../src/L1/L1ERC721Bridge.sol"; import { BlockOracle } from "src/dispute/BlockOracle.sol";
import { Predeploys } from "../src/libraries/Predeploys.sol"; import { L1ERC721Bridge } from "src/L1/L1ERC721Bridge.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
import { Chains } from "./Chains.sol"; import { Chains } from "./Chains.sol";
import { IBigStepper } from "../src/dispute/interfaces/IBigStepper.sol"; import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol";
import { AlphabetVM } from "../test/FaultDisputeGame.t.sol"; import { AlphabetVM } from "../test/FaultDisputeGame.t.sol";
import "../src/libraries/DisputeTypes.sol"; import "src/libraries/DisputeTypes.sol";
/// @title Deploy /// @title Deploy
/// @notice Script used to deploy a bedrock system. The entire system is deployed within the `run` function. /// @notice Script used to deploy a bedrock system. The entire system is deployed within the `run` function.
...@@ -719,10 +720,10 @@ contract Deploy is Deployer { ...@@ -719,10 +720,10 @@ contract Deploy is Deployer {
_maxGameDepth: cfg.faultGameMaxDepth(), _maxGameDepth: cfg.faultGameMaxDepth(),
_gameDuration: Duration.wrap(uint64(cfg.faultGameMaxDuration())), _gameDuration: Duration.wrap(uint64(cfg.faultGameMaxDuration())),
_vm: faultVm, _vm: faultVm,
_l2oo: L2OutputOracle(mustGetAddress("L2OutputOracleProxy")) _l2oo: L2OutputOracle(mustGetAddress("L2OutputOracleProxy")),
_blockOracle: new BlockOracle()
})); }));
console.log("DisputeGameFactory: set `FaultDisputeGame` implementation"); console.log("DisputeGameFactory: set `FaultDisputeGame` implementation");
} }
} }
} }
...@@ -5,16 +5,16 @@ ...@@ -5,16 +5,16 @@
"src/L1/L2OutputOracle.sol": "0x2b285a897d3285975bd47e89bd5ec7025369931384f9f02a20f48254dbfca181", "src/L1/L2OutputOracle.sol": "0x2b285a897d3285975bd47e89bd5ec7025369931384f9f02a20f48254dbfca181",
"src/L1/OptimismPortal.sol": "0xd5abaa3d1093c41f8e81b3cd298d4a35f90d103d9bca566a47ca562635f2f943", "src/L1/OptimismPortal.sol": "0xd5abaa3d1093c41f8e81b3cd298d4a35f90d103d9bca566a47ca562635f2f943",
"src/L1/SystemConfig.sol": "0xbd2be6c19e6e85eae73ddf3cd6304a395e2a41d86aee1c15b6b0f044bf54232e", "src/L1/SystemConfig.sol": "0xbd2be6c19e6e85eae73ddf3cd6304a395e2a41d86aee1c15b6b0f044bf54232e",
"src/L2/BaseFeeVault.sol": "0xc7bf7c43dd5362f6474fc3da8bb38d1c616ed2a3396486446482acf62cacfc2f", "src/L2/BaseFeeVault.sol": "0xaa2bf66e16ed9098af4251af94c30741f6ba094e321b786eff51b59574c6ad25",
"src/L2/GasPriceOracle.sol": "0x712134045fba966b0d0cc28019f5c2bd298d999649f387d989f744b274020a82", "src/L2/GasPriceOracle.sol": "0x712134045fba966b0d0cc28019f5c2bd298d999649f387d989f744b274020a82",
"src/L2/L1Block.sol": "0x64d2517a595a5b5af7eef1070920eb90aa595871ec55ba8b6d6aa323043ac000", "src/L2/L1Block.sol": "0x64d2517a595a5b5af7eef1070920eb90aa595871ec55ba8b6d6aa323043ac000",
"src/L2/L1FeeVault.sol": "0x49f6a1a89e83467e84110232f9e3c5fb2d0fad373f12afeef6b15d135a605659", "src/L2/L1FeeVault.sol": "0xc41752b9ce3d72b0f24c9baaa995e574e1a6b6166337485413a86c20f7063256",
"src/L2/L2CrossDomainMessenger.sol": "0xd1e057fe1889e0701f447af8016e4a201febdc28f640138878435746b3c6f647", "src/L2/L2CrossDomainMessenger.sol": "0xd1e057fe1889e0701f447af8016e4a201febdc28f640138878435746b3c6f647",
"src/L2/L2ERC721Bridge.sol": "0x2a0c241efb516161a12625e23d1e5aa32da815892e4fcc52f3b12d41cdff53b2", "src/L2/L2ERC721Bridge.sol": "0x2a0c241efb516161a12625e23d1e5aa32da815892e4fcc52f3b12d41cdff53b2",
"src/L2/L2StandardBridge.sol": "0x8ee5257e03ae4ba8555d9f7d13374c8a388315d62c16107bb4cadd450bfeb3d3", "src/L2/L2StandardBridge.sol": "0x8ee5257e03ae4ba8555d9f7d13374c8a388315d62c16107bb4cadd450bfeb3d3",
"src/L2/L2ToL1MessagePasser.sol": "0x7e35c3c4f1dd3d131dd71db07676301f7c477f02b6d6bf0ec468ecf2bed8325b", "src/L2/L2ToL1MessagePasser.sol": "0x7e35c3c4f1dd3d131dd71db07676301f7c477f02b6d6bf0ec468ecf2bed8325b",
"src/L2/SequencerFeeVault.sol": "0x17b30ccaed8b8dbe965c892cb8aae7f594fb4a87e0edd3ca6cd8f94559b86df9", "src/L2/SequencerFeeVault.sol": "0xd7266bada6ee69aa484d5d3c0590441b4475a786ba0c7c4872f2114fca96d9ee",
"src/dispute/FaultDisputeGame.sol": "0xb36f6456d74a9ee93df97bb6d5a554dcb531d730e6e2b10dd442897875f2ca81", "src/dispute/FaultDisputeGame.sol": "0x2a1e708bef8dda2760390cbabc1303dbe025752f40c32514bd8f61fdee84ffbe",
"src/legacy/DeployerWhitelist.sol": "0x47277d9c8409d517501d172db6697d55090d3d3a9e4bb2b1adea83471d793b6b", "src/legacy/DeployerWhitelist.sol": "0x47277d9c8409d517501d172db6697d55090d3d3a9e4bb2b1adea83471d793b6b",
"src/legacy/L1BlockNumber.sol": "0x1a1690b8b5ab53cf2b5c8e85fb86028b4078ae656286ae482cabe68374334f2a", "src/legacy/L1BlockNumber.sol": "0x1a1690b8b5ab53cf2b5c8e85fb86028b4078ae656286ae482cabe68374334f2a",
"src/legacy/LegacyMessagePasser.sol": "0xc7f42e6165507b4c50a5169a950f66602e6b4b8cff17f5d95994e121abb18390", "src/legacy/LegacyMessagePasser.sol": "0xc7f42e6165507b4c50a5169a950f66602e6b4b8cff17f5d95994e121abb18390",
......
...@@ -9,7 +9,7 @@ import { FeeVault } from "../universal/FeeVault.sol"; ...@@ -9,7 +9,7 @@ import { FeeVault } from "../universal/FeeVault.sol";
/// @title BaseFeeVault /// @title BaseFeeVault
/// @notice The BaseFeeVault accumulates the base fee that is paid by transactions. /// @notice The BaseFeeVault accumulates the base fee that is paid by transactions.
contract BaseFeeVault is FeeVault, Semver { contract BaseFeeVault is FeeVault, Semver {
/// @custom:semver 1.2.1 /// @custom:semver 1.3.0
/// @notice Constructs the BaseFeeVault contract. /// @notice Constructs the BaseFeeVault contract.
/// @param _recipient Wallet that will receive the fees. /// @param _recipient Wallet that will receive the fees.
/// @param _minWithdrawalAmount Minimum balance for withdrawals. /// @param _minWithdrawalAmount Minimum balance for withdrawals.
...@@ -18,5 +18,5 @@ contract BaseFeeVault is FeeVault, Semver { ...@@ -18,5 +18,5 @@ contract BaseFeeVault is FeeVault, Semver {
address _recipient, address _recipient,
uint256 _minWithdrawalAmount, uint256 _minWithdrawalAmount,
WithdrawalNetwork _withdrawalNetwork WithdrawalNetwork _withdrawalNetwork
) FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) Semver(1, 2, 1) {} ) FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) Semver(1, 3, 0) {}
} }
...@@ -9,7 +9,7 @@ import { FeeVault } from "../universal/FeeVault.sol"; ...@@ -9,7 +9,7 @@ import { FeeVault } from "../universal/FeeVault.sol";
/// @title L1FeeVault /// @title L1FeeVault
/// @notice The L1FeeVault accumulates the L1 portion of the transaction fees. /// @notice The L1FeeVault accumulates the L1 portion of the transaction fees.
contract L1FeeVault is FeeVault, Semver { contract L1FeeVault is FeeVault, Semver {
/// @custom:semver 1.2.1 /// @custom:semver 1.3.0
/// @notice Constructs the L1FeeVault contract. /// @notice Constructs the L1FeeVault contract.
/// @param _recipient Wallet that will receive the fees. /// @param _recipient Wallet that will receive the fees.
/// @param _minWithdrawalAmount Minimum balance for withdrawals. /// @param _minWithdrawalAmount Minimum balance for withdrawals.
...@@ -18,5 +18,5 @@ contract L1FeeVault is FeeVault, Semver { ...@@ -18,5 +18,5 @@ contract L1FeeVault is FeeVault, Semver {
address _recipient, address _recipient,
uint256 _minWithdrawalAmount, uint256 _minWithdrawalAmount,
WithdrawalNetwork _withdrawalNetwork WithdrawalNetwork _withdrawalNetwork
) FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) Semver(1, 2, 1) {} ) FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) Semver(1, 3, 0) {}
} }
...@@ -10,7 +10,7 @@ import { FeeVault } from "../universal/FeeVault.sol"; ...@@ -10,7 +10,7 @@ import { FeeVault } from "../universal/FeeVault.sol";
/// @notice The SequencerFeeVault is the contract that holds any fees paid to the Sequencer during /// @notice The SequencerFeeVault is the contract that holds any fees paid to the Sequencer during
/// transaction processing and block production. /// transaction processing and block production.
contract SequencerFeeVault is FeeVault, Semver { contract SequencerFeeVault is FeeVault, Semver {
/// @custom:semver 1.2.1 /// @custom:semver 1.3.0
/// @notice Constructs the SequencerFeeVault contract. /// @notice Constructs the SequencerFeeVault contract.
/// @param _recipient Wallet that will receive the fees. /// @param _recipient Wallet that will receive the fees.
/// @param _minWithdrawalAmount Minimum balance for withdrawals. /// @param _minWithdrawalAmount Minimum balance for withdrawals.
...@@ -19,7 +19,7 @@ contract SequencerFeeVault is FeeVault, Semver { ...@@ -19,7 +19,7 @@ contract SequencerFeeVault is FeeVault, Semver {
address _recipient, address _recipient,
uint256 _minWithdrawalAmount, uint256 _minWithdrawalAmount,
WithdrawalNetwork _withdrawalNetwork WithdrawalNetwork _withdrawalNetwork
) FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) Semver(1, 2, 1) {} ) FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) Semver(1, 3, 0) {}
/// @custom:legacy /// @custom:legacy
/// @notice Legacy getter for the recipient address. /// @notice Legacy getter for the recipient address.
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import "src/libraries/DisputeTypes.sol";
import "src/libraries/DisputeErrors.sol";
/// @title BlockOracle
/// @notice Stores a map of block numbers => block hashes for use in dispute resolution
contract BlockOracle {
/// @notice The BlockInfo struct contains a block's hash and child timestamp.
struct BlockInfo {
Hash hash;
Timestamp childTimestamp;
}
/// @notice Emitted when a block is checkpointed.
event Checkpoint(
uint256 indexed blockNumber,
Hash indexed blockHash,
Timestamp indexed childTimestamp
);
/// @notice Maps block numbers to block hashes and timestamps
mapping(uint256 => BlockInfo) internal blocks;
/// @notice Loads a block hash for a given block number, assuming that the block number
/// has been stored in the oracle.
/// @param _blockNumber The block number to load the block hash and timestamp for.
/// @return blockInfo_ The block hash and timestamp for the given block number.
function load(uint256 _blockNumber) external view returns (BlockInfo memory blockInfo_) {
blockInfo_ = blocks[_blockNumber];
if (Hash.unwrap(blockInfo_.hash) == 0) revert BlockHashNotPresent();
}
/// @notice Stores a block hash for the previous block number.
/// @return blockNumber_ The block number that was checkpointed, which is always
/// `block.number - 1`.
function checkpoint() external returns (uint256 blockNumber_) {
// SAFETY: This block hash will always be accessible by the `BLOCKHASH` opcode,
// and in the case of `block.number = 0`, we'll underflow.
// Persist the block information.
blockNumber_ = block.number - 1;
Hash blockHash = Hash.wrap(blockhash(blockNumber_));
Timestamp childTimestamp = Timestamp.wrap(uint64(block.timestamp));
blocks[blockNumber_] = BlockInfo({ hash: blockHash, childTimestamp: childTimestamp });
emit Checkpoint(blockNumber_, blockHash, childTimestamp);
}
}
...@@ -18,6 +18,20 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -18,6 +18,20 @@ interface IFaultDisputeGame is IDisputeGame {
Clock clock; Clock clock;
} }
/// @notice The `OutputProposal` struct contains information about an output proposal in
/// the `L2OutputOracle` at a given index.
struct OutputProposal {
uint128 index;
uint128 l2BlockNumber;
Hash outputRoot;
}
/// @notice A container for two consecutive `OutputProposal`s.
struct OutputProposals {
OutputProposal starting;
OutputProposal disputed;
}
/// @notice Emitted when a new claim is added to the DAG by `claimant` /// @notice Emitted when a new claim is added to the DAG by `claimant`
/// @param parentIndex The index within the `claimData` array of the parent claim /// @param parentIndex The index within the `claimData` array of the parent claim
/// @param claim The claim being added /// @param claim The claim being added
...@@ -63,6 +77,8 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -63,6 +77,8 @@ interface IFaultDisputeGame is IDisputeGame {
/// @notice The l2BlockNumber that the `rootClaim` commits to. The trace being bisected within /// @notice The l2BlockNumber that the `rootClaim` commits to. The trace being bisected within
/// the game is from `l2BlockNumber - 1` -> `l2BlockNumber`. /// the game is from `l2BlockNumber - 1` -> `l2BlockNumber`.
/// @return l2BlockNumber_ The l2BlockNumber that the `rootClaim` commits to.
function l2BlockNumber() external view returns (uint256 l2BlockNumber_); function l2BlockNumber() external view returns (uint256 l2BlockNumber_);
/// @notice The l1BlockNumber that Cannon was ran from to generate the root claim.
function l1BlockNumber() external view returns (uint256 l1BlockNumber_);
} }
...@@ -16,7 +16,7 @@ error NoImplementation(GameType gameType); ...@@ -16,7 +16,7 @@ error NoImplementation(GameType gameType);
error GameAlreadyExists(Hash uuid); error GameAlreadyExists(Hash uuid);
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// `DisputeGame_Fault.sol` Errors // // `FaultDisputeGame` Errors //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
/// @notice Thrown when a supplied bond is too low to cover the /// @notice Thrown when a supplied bond is too low to cover the
...@@ -54,6 +54,10 @@ error InvalidPrestate(); ...@@ -54,6 +54,10 @@ error InvalidPrestate();
/// @notice Thrown when a step is made that computes the expected post state correctly. /// @notice Thrown when a step is made that computes the expected post state correctly.
error ValidStep(); error ValidStep();
/// @notice Thrown when a game is attempted to be initialized with an L1 head that does
/// not contain the disputed output root.
error L1HeadTooOld();
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// `AttestationDisputeGame` Errors // // `AttestationDisputeGame` Errors //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
...@@ -72,3 +76,14 @@ error AlreadyChallenged(); ...@@ -72,3 +76,14 @@ error AlreadyChallenged();
/// @notice Thrown when a function that is protected by the `onlyOwner` modifier /// @notice Thrown when a function that is protected by the `onlyOwner` modifier
/// is called from an account other than the owner. /// is called from an account other than the owner.
error NotOwner(); error NotOwner();
////////////////////////////////////////////////////////////////
// `BlockOracle` Errors //
////////////////////////////////////////////////////////////////
/// @notice Thrown when a block that is out of the range of the `BLOCKHASH` opcode
/// is attempted to be loaded.
error BlockNumberOOB();
/// @notice Thrown when a block hash is attempted to be loaded that has not been stored.
error BlockHashNotPresent();
...@@ -3,7 +3,6 @@ pragma solidity 0.8.15; ...@@ -3,7 +3,6 @@ pragma solidity 0.8.15;
import { L2StandardBridge } from "../L2/L2StandardBridge.sol"; import { L2StandardBridge } from "../L2/L2StandardBridge.sol";
import { Predeploys } from "../libraries/Predeploys.sol"; import { Predeploys } from "../libraries/Predeploys.sol";
import { SafeCall } from "../libraries/SafeCall.sol";
/// @title FeeVault /// @title FeeVault
/// @notice The FeeVault contract contains the basic logic for the various different vault contracts /// @notice The FeeVault contract contains the basic logic for the various different vault contracts
...@@ -76,7 +75,8 @@ abstract contract FeeVault { ...@@ -76,7 +75,8 @@ abstract contract FeeVault {
emit Withdrawal(value, RECIPIENT, msg.sender, WITHDRAWAL_NETWORK); emit Withdrawal(value, RECIPIENT, msg.sender, WITHDRAWAL_NETWORK);
if (WITHDRAWAL_NETWORK == WithdrawalNetwork.L2) { if (WITHDRAWAL_NETWORK == WithdrawalNetwork.L2) {
SafeCall.send(RECIPIENT, gasleft(), value); (bool success, ) = RECIPIENT.call{ value: value }(hex"");
require(success, "FeeVault: failed to send ETH to L2 fee recipient");
} else { } else {
L2StandardBridge(payable(Predeploys.L2_STANDARD_BRIDGE)).bridgeETHTo{ value: value }( L2StandardBridge(payable(Predeploys.L2_STANDARD_BRIDGE)).bridgeETHTo{ value: value }(
RECIPIENT, RECIPIENT,
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
import { BlockOracle } from "src/dispute/BlockOracle.sol";
import "src/libraries/DisputeTypes.sol";
import "src/libraries/DisputeErrors.sol";
contract BlockOracle_Test is Test {
BlockOracle oracle;
/// @notice Emitted when a block is checkpointed.
event Checkpoint(
uint256 indexed blockNumber,
Hash indexed blockHash,
Timestamp indexed childTimestamp
);
function setUp() public {
oracle = new BlockOracle();
// Roll the chain forward 1 block.
vm.roll(block.number + 1);
vm.warp(block.timestamp + 13);
}
/// @notice Tests that checkpointing a block and loading its information succeeds.
function test_checkpointAndLoad_succeeds() public {
vm.expectEmit(true, true, true, false);
emit Checkpoint(
block.number - 1,
Hash.wrap(blockhash(block.number - 1)),
Timestamp.wrap(uint64(block.timestamp))
);
oracle.checkpoint();
uint256 blockNumber = block.number - 1;
BlockOracle.BlockInfo memory res = oracle.load(blockNumber);
assertEq(Hash.unwrap(res.hash), blockhash(blockNumber));
assertEq(Timestamp.unwrap(res.childTimestamp), block.timestamp);
}
/// @notice Tests that the `load` function reverts if the block hash for the given block
/// number has not been stored.
function test_load_noBlockHash_reverts() public {
vm.expectRevert(BlockHashNotPresent.selector);
oracle.load(0);
}
}
...@@ -8,8 +8,9 @@ import { Test } from "forge-std/Test.sol"; ...@@ -8,8 +8,9 @@ import { Test } from "forge-std/Test.sol";
import { DisputeGameFactory } from "../src/dispute/DisputeGameFactory.sol"; import { DisputeGameFactory } from "../src/dispute/DisputeGameFactory.sol";
import { IDisputeGame } from "../src/dispute/interfaces/IDisputeGame.sol"; import { IDisputeGame } from "../src/dispute/interfaces/IDisputeGame.sol";
import { Proxy } from "../src/universal/Proxy.sol"; import { Proxy } from "../src/universal/Proxy.sol";
import { L2OutputOracle_Initializer } from "./CommonTest.t.sol";
contract DisputeGameFactory_Init is Test { contract DisputeGameFactory_Init is L2OutputOracle_Initializer {
DisputeGameFactory factory; DisputeGameFactory factory;
FakeClone fakeClone; FakeClone fakeClone;
...@@ -21,7 +22,9 @@ contract DisputeGameFactory_Init is Test { ...@@ -21,7 +22,9 @@ contract DisputeGameFactory_Init is Test {
event ImplementationSet(address indexed impl, GameType indexed gameType); event ImplementationSet(address indexed impl, GameType indexed gameType);
function setUp() public virtual { function setUp() public virtual override {
super.setUp();
Proxy proxy = new Proxy(address(this)); Proxy proxy = new Proxy(address(this));
DisputeGameFactory impl = new DisputeGameFactory(); DisputeGameFactory impl = new DisputeGameFactory();
......
...@@ -7,16 +7,16 @@ import { DisputeGameFactory_Init } from "./DisputeGameFactory.t.sol"; ...@@ -7,16 +7,16 @@ import { DisputeGameFactory_Init } from "./DisputeGameFactory.t.sol";
import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol"; import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { FaultDisputeGame } from "src/dispute/FaultDisputeGame.sol"; import { FaultDisputeGame } from "src/dispute/FaultDisputeGame.sol";
import { L2OutputOracle } from "src/L1/L2OutputOracle.sol"; import { L2OutputOracle } from "src/L1/L2OutputOracle.sol";
import { BlockOracle } from "src/dispute/BlockOracle.sol";
import "src/libraries/DisputeTypes.sol"; import "src/libraries/DisputeTypes.sol";
import "src/libraries/DisputeErrors.sol"; import "src/libraries/DisputeErrors.sol";
import { Types } from "src/libraries/Types.sol";
import { LibClock } from "src/dispute/lib/LibClock.sol"; import { LibClock } from "src/dispute/lib/LibClock.sol";
import { LibPosition } from "src/dispute/lib/LibPosition.sol"; import { LibPosition } from "src/dispute/lib/LibPosition.sol";
import { IBigStepper, IPreimageOracle } from "src/dispute/interfaces/IBigStepper.sol"; import { IBigStepper, IPreimageOracle } from "src/dispute/interfaces/IBigStepper.sol";
contract FaultDisputeGame_Init is DisputeGameFactory_Init { contract FaultDisputeGame_Init is DisputeGameFactory_Init {
/// @dev The extra data passed to the game for initialization.
bytes internal constant EXTRA_DATA = abi.encode(1);
/// @dev The type of the game being tested. /// @dev The type of the game being tested.
GameType internal constant GAME_TYPE = GameType.wrap(0); GameType internal constant GAME_TYPE = GameType.wrap(0);
...@@ -24,24 +24,53 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init { ...@@ -24,24 +24,53 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init {
FaultDisputeGame internal gameImpl; FaultDisputeGame internal gameImpl;
/// @dev The `Clone` proxy of the game. /// @dev The `Clone` proxy of the game.
FaultDisputeGame internal gameProxy; FaultDisputeGame internal gameProxy;
/// @dev The extra data passed to the game for initialization.
bytes internal extraData;
event Move(uint256 indexed parentIndex, Claim indexed pivot, address indexed claimant); event Move(uint256 indexed parentIndex, Claim indexed pivot, address indexed claimant);
function init(Claim rootClaim, Claim absolutePrestate) public { function init(Claim rootClaim, Claim absolutePrestate) public {
super.setUp(); super.setUp();
// Set the time to a realistic date.
vm.warp(1690906994);
// Propose 2 mock outputs
vm.startPrank(oracle.PROPOSER());
for (uint256 i; i < 2; i++) {
oracle.proposeL2Output(
bytes32(i + 1),
oracle.nextBlockNumber(),
blockhash(i),
i
);
// Advance 1 block
vm.roll(block.number + 1);
vm.warp(block.timestamp + 13);
}
vm.stopPrank();
// Deploy a new block hash oracle and store the block hash for the genesis block.
BlockOracle blockOracle = new BlockOracle();
blockOracle.checkpoint();
// Set the extra data for the game creation
extraData = abi.encode(oracle.SUBMISSION_INTERVAL() * 2, block.number - 1);
// Deploy an implementation of the fault game // Deploy an implementation of the fault game
gameImpl = new FaultDisputeGame( gameImpl = new FaultDisputeGame(
absolutePrestate, absolutePrestate,
4, 4,
Duration.wrap(7 days), Duration.wrap(7 days),
new AlphabetVM(absolutePrestate), new AlphabetVM(absolutePrestate),
L2OutputOracle(deployNoop()) oracle,
blockOracle
); );
// Register the game implementation with the factory. // Register the game implementation with the factory.
factory.setImplementation(GAME_TYPE, gameImpl); factory.setImplementation(GAME_TYPE, gameImpl);
// Create a new game. // Create a new game.
gameProxy = FaultDisputeGame(address(factory.create(GAME_TYPE, rootClaim, EXTRA_DATA))); gameProxy = FaultDisputeGame(address(factory.create(GAME_TYPE, rootClaim, extraData)));
// Label the proxy // Label the proxy
vm.label(address(gameProxy), "FaultDisputeGame_Clone"); vm.label(address(gameProxy), "FaultDisputeGame_Clone");
...@@ -69,7 +98,7 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init { ...@@ -69,7 +98,7 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
/// @dev Tests that the game's extra data is set correctly. /// @dev Tests that the game's extra data is set correctly.
function test_extraData_succeeds() public { function test_extraData_succeeds() public {
assertEq(gameProxy.extraData(), EXTRA_DATA); assertEq(gameProxy.extraData(), extraData);
} }
/// @dev Tests that the game's status is set correctly. /// @dev Tests that the game's status is set correctly.
...@@ -84,19 +113,56 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init { ...@@ -84,19 +113,56 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
/// @dev Tests that the game's data is set correctly. /// @dev Tests that the game's data is set correctly.
function test_gameData_succeeds() public { function test_gameData_succeeds() public {
(GameType gameType, Claim rootClaim, bytes memory extraData) = gameProxy.gameData(); (GameType gameType, Claim rootClaim, bytes memory _extraData) = gameProxy.gameData();
assertEq(GameType.unwrap(gameType), GameType.unwrap(GAME_TYPE)); assertEq(GameType.unwrap(gameType), GameType.unwrap(GAME_TYPE));
assertEq(Claim.unwrap(rootClaim), Claim.unwrap(ROOT_CLAIM)); assertEq(Claim.unwrap(rootClaim), Claim.unwrap(ROOT_CLAIM));
assertEq(extraData, EXTRA_DATA); assertEq(_extraData, extraData);
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// `IFaultDisputeGame` Implementation Tests // // `IFaultDisputeGame` Implementation Tests //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
/// @dev Tests that the root claim's data is set correctly when the game is initialized. /// @dev Tests that a game cannot be created by the factory if the L1 head hash does not
function test_initialRootClaimData_succeeds() public { /// contain the disputed L2 output root.
function test_initialize_l1HeadTooOld_reverts() public {
// Store a mock block hash for the genesis block. The timestamp will default to 0.
vm.store(address(gameImpl.BLOCK_ORACLE()), keccak256(abi.encode(0, 0)), bytes32(uint256(1)));
bytes memory _extraData = abi.encode(oracle.SUBMISSION_INTERVAL() * 2, 0);
vm.expectRevert(L1HeadTooOld.selector);
factory.create(GAME_TYPE, ROOT_CLAIM, _extraData);
}
/// @dev Tests that a game cannot be created that disputes the first output root proposed.
/// TODO(clabby): This will be solved by the block hash bisection game, where we'll be able
/// to dispute the first output root by using genesis as the starting point.
/// For now, it is critical that the first proposed output root of an OP stack
/// chain is done so by an honest party.
function test_initialize_firstOutput_reverts() public {
vm.expectRevert(abi.encodeWithSignature("Panic(uint256)", 0x11));
factory.create(GAME_TYPE, ROOT_CLAIM, abi.encode(1800, block.number - 1));
}
/// @dev Tests that the game is initialized with the correct data.
function test_initialize_correctData_succeeds() public {
// Starting
(FaultDisputeGame.OutputProposal memory startingProp, FaultDisputeGame.OutputProposal memory disputedProp) = gameProxy.proposals();
Types.OutputProposal memory starting = oracle.getL2Output(startingProp.index);
assertEq(startingProp.index, 0);
assertEq(startingProp.l2BlockNumber, starting.l2BlockNumber);
assertEq(Hash.unwrap(startingProp.outputRoot), starting.outputRoot);
// Disputed
Types.OutputProposal memory disputed = oracle.getL2Output(disputedProp.index);
assertEq(disputedProp.index, 1);
assertEq(disputedProp.l2BlockNumber, disputed.l2BlockNumber);
assertEq(Hash.unwrap(disputedProp.outputRoot), disputed.outputRoot);
// L1 head
(, uint256 l1HeadNumber) = abi.decode(gameProxy.extraData(), (uint256, uint256));
assertEq(blockhash(l1HeadNumber), Hash.unwrap(gameProxy.l1Head()));
( (
uint32 parentIndex, uint32 parentIndex,
bool countered, bool countered,
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
// Testing utilities // Testing utilities
import { FeeVault_Initializer } from "./CommonTest.t.sol"; import { FeeVault_Initializer, Reverter } from "./CommonTest.t.sol";
import { StandardBridge } from "../src/universal/StandardBridge.sol"; import { StandardBridge } from "../src/universal/StandardBridge.sol";
// Libraries // Libraries
...@@ -137,4 +137,25 @@ contract SequencerFeeVault_L2Withdrawal_Test is FeeVault_Initializer { ...@@ -137,4 +137,25 @@ contract SequencerFeeVault_L2Withdrawal_Test is FeeVault_Initializer {
assertEq(address(vault).balance, ZERO_VALUE); assertEq(address(vault).balance, ZERO_VALUE);
assertEq(recipient.balance, amount); assertEq(recipient.balance, amount);
} }
/// @dev Tests that `withdraw` fails if the Recipient reverts. This also serves to simulate
/// a situation where insufficient gas is provided to the RECIPIENT.
function test_withdraw_toL2recipientReverts_fails() external {
uint256 amount = vault.MIN_WITHDRAWAL_AMOUNT();
vm.deal(address(vault), amount);
// No ether has been withdrawn yet
assertEq(vault.totalProcessed(), 0);
// Ensure the RECIPIENT reverts
vm.etch(vault.RECIPIENT(), type(Reverter).runtimeCode);
// The entire vault's balance is withdrawn
vm.expectCall(recipient, address(vault).balance, bytes(""));
vm.expectRevert(
"FeeVault: failed to send ETH to L2 fee recipient"
);
vault.withdraw();
assertEq(vault.totalProcessed(), 0);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment