Commit 8809a31f authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

Merge pull request #8201 from ethereum-optimism/aj/create-cannon

op-challenger: Translate pre/post claims into output root proposals
parents dd7bcef7 0d9e6015
...@@ -36,12 +36,27 @@ type FaultDisputeGameContract struct { ...@@ -36,12 +36,27 @@ type FaultDisputeGameContract struct {
contract *batching.BoundContract contract *batching.BoundContract
} }
type Proposal struct { // contractProposal matches the structure for output root proposals used by the contracts.
// It must exactly match the contract structure. The exposed API uses Proposal to decouple the contract
// and challenger representations of the proposal data.
type contractProposal struct {
Index *big.Int Index *big.Int
L2BlockNumber *big.Int L2BlockNumber *big.Int
OutputRoot common.Hash OutputRoot common.Hash
} }
type Proposal struct {
L2BlockNumber *big.Int
OutputRoot common.Hash
}
func asProposal(p contractProposal) Proposal {
return Proposal{
L2BlockNumber: p.L2BlockNumber,
OutputRoot: p.OutputRoot,
}
}
func NewFaultDisputeGameContract(addr common.Address, caller *batching.MultiCaller) (*FaultDisputeGameContract, error) { func NewFaultDisputeGameContract(addr common.Address, caller *batching.MultiCaller) (*FaultDisputeGameContract, error) {
fdgAbi, err := bindings.FaultDisputeGameMetaData.GetAbi() fdgAbi, err := bindings.FaultDisputeGameMetaData.GetAbi()
if err != nil { if err != nil {
...@@ -93,10 +108,10 @@ func (f *FaultDisputeGameContract) GetProposals(ctx context.Context) (Proposal, ...@@ -93,10 +108,10 @@ func (f *FaultDisputeGameContract) GetProposals(ctx context.Context) (Proposal,
return Proposal{}, Proposal{}, fmt.Errorf("failed to fetch proposals: %w", err) return Proposal{}, Proposal{}, fmt.Errorf("failed to fetch proposals: %w", err)
} }
var agreed, disputed Proposal var agreed, disputed contractProposal
result.GetStruct(0, &agreed) result.GetStruct(0, &agreed)
result.GetStruct(1, &disputed) result.GetStruct(1, &disputed)
return agreed, disputed, nil return asProposal(agreed), asProposal(disputed), nil
} }
func (f *FaultDisputeGameContract) GetStatus(ctx context.Context) (gameTypes.GameStatus, error) { func (f *FaultDisputeGameContract) GetStatus(ctx context.Context) (gameTypes.GameStatus, error) {
...@@ -217,7 +232,7 @@ func (f *FaultDisputeGameContract) addLocalDataTx(data *types.PreimageOracleData ...@@ -217,7 +232,7 @@ func (f *FaultDisputeGameContract) addLocalDataTx(data *types.PreimageOracleData
call := f.contract.Call( call := f.contract.Call(
methodAddLocalData, methodAddLocalData,
data.GetIdent(), data.GetIdent(),
new(big.Int).SetUint64(data.LocalContext), new(big.Int).SetBytes(data.LocalContext.Bytes()),
new(big.Int).SetUint64(uint64(data.OracleOffset)), new(big.Int).SetUint64(uint64(data.OracleOffset)),
) )
return call.ToTxCandidate() return call.ToTxCandidate()
......
...@@ -105,23 +105,31 @@ func TestGetProposals(t *testing.T) { ...@@ -105,23 +105,31 @@ func TestGetProposals(t *testing.T) {
disputedIndex := big.NewInt(7) disputedIndex := big.NewInt(7)
disputedBlockNum := big.NewInt(8) disputedBlockNum := big.NewInt(8)
disputedRoot := common.Hash{0xdd} disputedRoot := common.Hash{0xdd}
agreed := Proposal{ agreed := contractProposal{
Index: agreedIndex, Index: agreedIndex,
L2BlockNumber: agreedBlockNum, L2BlockNumber: agreedBlockNum,
OutputRoot: agreedRoot, OutputRoot: agreedRoot,
} }
disputed := Proposal{ disputed := contractProposal{
Index: disputedIndex, Index: disputedIndex,
L2BlockNumber: disputedBlockNum, L2BlockNumber: disputedBlockNum,
OutputRoot: disputedRoot, OutputRoot: disputedRoot,
} }
expectedAgreed := Proposal{
L2BlockNumber: agreed.L2BlockNumber,
OutputRoot: agreed.OutputRoot,
}
expectedDisputed := Proposal{
L2BlockNumber: disputed.L2BlockNumber,
OutputRoot: disputed.OutputRoot,
}
stubRpc.SetResponse(fdgAddr, methodProposals, batching.BlockLatest, []interface{}{}, []interface{}{ stubRpc.SetResponse(fdgAddr, methodProposals, batching.BlockLatest, []interface{}{}, []interface{}{
agreed, disputed, agreed, disputed,
}) })
actualAgreed, actualDisputed, err := game.GetProposals(context.Background()) actualAgreed, actualDisputed, err := game.GetProposals(context.Background())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, agreed, actualAgreed) require.Equal(t, expectedAgreed, actualAgreed)
require.Equal(t, disputed, actualDisputed) require.Equal(t, expectedDisputed, actualDisputed)
} }
func TestGetClaim(t *testing.T) { func TestGetClaim(t *testing.T) {
...@@ -245,14 +253,14 @@ func TestUpdateOracleTx(t *testing.T) { ...@@ -245,14 +253,14 @@ func TestUpdateOracleTx(t *testing.T) {
stubRpc, game := setup(t) stubRpc, game := setup(t)
data := &faultTypes.PreimageOracleData{ data := &faultTypes.PreimageOracleData{
IsLocal: true, IsLocal: true,
LocalContext: 2, LocalContext: common.Hash{0x02},
OracleKey: common.Hash{0xbc}.Bytes(), OracleKey: common.Hash{0xbc}.Bytes(),
OracleData: []byte{1, 2, 3, 4, 5, 6, 7}, OracleData: []byte{1, 2, 3, 4, 5, 6, 7},
OracleOffset: 16, OracleOffset: 16,
} }
stubRpc.SetResponse(fdgAddr, methodAddLocalData, batching.BlockLatest, []interface{}{ stubRpc.SetResponse(fdgAddr, methodAddLocalData, batching.BlockLatest, []interface{}{
data.GetIdent(), data.GetIdent(),
new(big.Int).SetUint64(data.LocalContext), new(big.Int).SetBytes(data.LocalContext.Bytes()),
new(big.Int).SetUint64(uint64(data.OracleOffset)), new(big.Int).SetUint64(uint64(data.OracleOffset)),
}, nil) }, nil)
tx, err := game.UpdateOracleTx(context.Background(), data) tx, err := game.UpdateOracleTx(context.Background(), data)
......
...@@ -91,7 +91,7 @@ func registerCannon( ...@@ -91,7 +91,7 @@ func registerCannon(
client *ethclient.Client) { client *ethclient.Client) {
resourceCreator := func(addr common.Address, contract *contracts.FaultDisputeGameContract, gameDepth uint64, dir string) (faultTypes.TraceAccessor, gameValidator, error) { resourceCreator := func(addr common.Address, contract *contracts.FaultDisputeGameContract, gameDepth uint64, dir string) (faultTypes.TraceAccessor, gameValidator, error) {
logger := logger.New("game", addr) logger := logger.New("game", addr)
provider, err := cannon.NewTraceProvider(ctx, logger, m, cfg, contract, cannon.NoLocalContext, dir, gameDepth) provider, err := cannon.NewTraceProvider(ctx, logger, m, cfg, contract, faultTypes.NoLocalContext, dir, gameDepth)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("create cannon trace provider: %w", err) return nil, nil, fmt.Errorf("create cannon trace provider: %w", err)
} }
......
...@@ -180,7 +180,7 @@ func TestPerformAction(t *testing.T) { ...@@ -180,7 +180,7 @@ func TestPerformAction(t *testing.T) {
ProofData: []byte{4, 5, 6}, ProofData: []byte{4, 5, 6},
OracleData: &types.PreimageOracleData{ OracleData: &types.PreimageOracleData{
IsLocal: true, IsLocal: true,
LocalContext: 6, LocalContext: common.Hash{0x06},
}, },
} }
err := responder.PerformAction(context.Background(), action) err := responder.PerformAction(context.Background(), action)
......
...@@ -33,6 +33,6 @@ func (a *alphabetWithProofProvider) GetStepData(ctx context.Context, i types.Pos ...@@ -33,6 +33,6 @@ func (a *alphabetWithProofProvider) GetStepData(ctx context.Context, i types.Pos
return nil, nil, nil, err return nil, nil, nil, err
} }
traceIndex := i.TraceIndex(int(a.depth)).Uint64() traceIndex := i.TraceIndex(int(a.depth)).Uint64()
data := types.NewPreimageOracleData(0, []byte{byte(traceIndex)}, []byte{byte(traceIndex - 1)}, uint32(traceIndex-1)) data := types.NewPreimageOracleData(types.NoLocalContext, []byte{byte(traceIndex)}, []byte{byte(traceIndex - 1)}, uint32(traceIndex-1))
return preimage, []byte{byte(traceIndex - 1)}, data, nil return preimage, []byte{byte(traceIndex - 1)}, data, nil
} }
...@@ -17,12 +17,10 @@ func TestFetchLocalInputs(t *testing.T) { ...@@ -17,12 +17,10 @@ func TestFetchLocalInputs(t *testing.T) {
contract := &mockGameInputsSource{ contract := &mockGameInputsSource{
l1Head: common.Hash{0xcc}, l1Head: common.Hash{0xcc},
starting: contracts.Proposal{ starting: contracts.Proposal{
Index: big.NewInt(6),
L2BlockNumber: big.NewInt(2222), L2BlockNumber: big.NewInt(2222),
OutputRoot: common.Hash{0xdd}, OutputRoot: common.Hash{0xdd},
}, },
disputed: contracts.Proposal{ disputed: contracts.Proposal{
Index: big.NewInt(7),
L2BlockNumber: big.NewInt(3333), L2BlockNumber: big.NewInt(3333),
OutputRoot: common.Hash{0xee}, OutputRoot: common.Hash{0xee},
}, },
......
...@@ -23,10 +23,6 @@ import ( ...@@ -23,10 +23,6 @@ import (
const ( const (
proofsDir = "proofs" proofsDir = "proofs"
diskStateCache = "state.json.gz" diskStateCache = "state.json.gz"
// NoLocalContext is the LocalContext value used when the cannon trace provider is used alone instead of as part
// of a split game.
NoLocalContext = 0
) )
type proofData struct { type proofData struct {
...@@ -53,14 +49,14 @@ type CannonTraceProvider struct { ...@@ -53,14 +49,14 @@ type CannonTraceProvider struct {
prestate string prestate string
generator ProofGenerator generator ProofGenerator
gameDepth uint64 gameDepth uint64
localContext uint64 localContext common.Hash
// lastStep stores the last step in the actual trace if known. 0 indicates unknown. // lastStep stores the last step in the actual trace if known. 0 indicates unknown.
// Cached as an optimisation to avoid repeatedly attempting to execute beyond the end of the trace. // Cached as an optimisation to avoid repeatedly attempting to execute beyond the end of the trace.
lastStep uint64 lastStep uint64
} }
func NewTraceProvider(ctx context.Context, logger log.Logger, m CannonMetricer, cfg *config.Config, gameContract *contracts.FaultDisputeGameContract, localContext uint64, dir string, gameDepth uint64) (*CannonTraceProvider, error) { func NewTraceProvider(ctx context.Context, logger log.Logger, m CannonMetricer, cfg *config.Config, gameContract *contracts.FaultDisputeGameContract, localContext common.Hash, dir string, gameDepth uint64) (*CannonTraceProvider, error) {
l2Client, err := ethclient.DialContext(ctx, cfg.CannonL2) l2Client, err := ethclient.DialContext(ctx, cfg.CannonL2)
if err != nil { if err != nil {
return nil, fmt.Errorf("dial l2 client %v: %w", cfg.CannonL2, err) return nil, fmt.Errorf("dial l2 client %v: %w", cfg.CannonL2, err)
...@@ -73,7 +69,7 @@ func NewTraceProvider(ctx context.Context, logger log.Logger, m CannonMetricer, ...@@ -73,7 +69,7 @@ func NewTraceProvider(ctx context.Context, logger log.Logger, m CannonMetricer,
return NewTraceProviderFromInputs(logger, m, cfg, localContext, localInputs, dir, gameDepth), nil return NewTraceProviderFromInputs(logger, m, cfg, localContext, localInputs, dir, gameDepth), nil
} }
func NewTraceProviderFromInputs(logger log.Logger, m CannonMetricer, cfg *config.Config, localContext uint64, localInputs LocalGameInputs, dir string, gameDepth uint64) *CannonTraceProvider { func NewTraceProviderFromInputs(logger log.Logger, m CannonMetricer, cfg *config.Config, localContext common.Hash, localInputs LocalGameInputs, dir string, gameDepth uint64) *CannonTraceProvider {
return &CannonTraceProvider{ return &CannonTraceProvider{
logger: logger, logger: logger,
dir: dir, dir: dir,
......
...@@ -124,7 +124,7 @@ func TestGetStepData(t *testing.T) { ...@@ -124,7 +124,7 @@ func TestGetStepData(t *testing.T) {
require.EqualValues(t, generator.proof.StateData, preimage) require.EqualValues(t, generator.proof.StateData, preimage)
require.EqualValues(t, generator.proof.ProofData, proof) require.EqualValues(t, generator.proof.ProofData, proof)
expectedData := types.NewPreimageOracleData(0, generator.proof.OracleKey, generator.proof.OracleValue, generator.proof.OracleOffset) expectedData := types.NewPreimageOracleData(common.Hash{}, generator.proof.OracleKey, generator.proof.OracleValue, generator.proof.OracleOffset)
require.EqualValues(t, expectedData, data) require.EqualValues(t, expectedData, data)
}) })
......
...@@ -4,8 +4,11 @@ import ( ...@@ -4,8 +4,11 @@ import (
"context" "context"
"errors" "errors"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/split"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
...@@ -16,11 +19,11 @@ func NewOutputCannonTraceAccessor(ctx context.Context, logger log.Logger, rollup ...@@ -16,11 +19,11 @@ func NewOutputCannonTraceAccessor(ctx context.Context, logger log.Logger, rollup
return nil, err return nil, err
} }
cannonCreator := func(ctx context.Context, pre types.Claim, post types.Claim) (types.TraceProvider, error) { cannonCreator := func(ctx context.Context, localContext common.Hash, agreed contracts.Proposal, claimed contracts.Proposal) (types.TraceProvider, error) {
// TODO(client-pod#43): Actually create the cannon trace provider for the trace between the given claims. // TODO(client-pod#43): Actually create the cannon trace provider for the trace between the given claims.
return nil, errors.New("not implemented") return nil, errors.New("not implemented")
} }
selector := newSplitProviderSelector(outputProvider, int(topDepth), cannonCreator) selector := split.NewSplitProviderSelector(outputProvider, int(topDepth), OutputRootSplitAdapter(outputProvider, cannonCreator))
return trace.NewAccessor(selector), nil return trace.NewAccessor(selector), nil
} }
package outputs
import (
"context"
"fmt"
"math/big"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/split"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
type ProposalTraceProviderCreator func(ctx context.Context, localContext common.Hash, agreed contracts.Proposal, claimed contracts.Proposal) (types.TraceProvider, error)
func OutputRootSplitAdapter(topProvider *OutputTraceProvider, creator ProposalTraceProviderCreator) split.ProviderCreator {
return func(ctx context.Context, pre types.Claim, post types.Claim) (types.TraceProvider, error) {
localContext := createLocalContext(pre, post)
usePrestateBlock := pre == (types.Claim{})
var agreed contracts.Proposal
if usePrestateBlock {
prestateRoot, err := topProvider.AbsolutePreStateCommitment(ctx)
if err != nil {
return nil, fmt.Errorf("failed to retrieve absolute prestate output root: %w", err)
}
agreed = contracts.Proposal{
L2BlockNumber: new(big.Int).SetUint64(topProvider.prestateBlock),
OutputRoot: prestateRoot,
}
} else {
preBlockNum, err := topProvider.BlockNumber(pre.Position)
if err != nil {
return nil, fmt.Errorf("unable to calculate pre-claim block number: %w", err)
}
agreed = contracts.Proposal{
L2BlockNumber: new(big.Int).SetUint64(preBlockNum),
OutputRoot: pre.Value,
}
}
postBlockNum, err := topProvider.BlockNumber(post.Position)
if err != nil {
return nil, fmt.Errorf("unable to calculate post-claim block number: %w", err)
}
claimed := contracts.Proposal{
L2BlockNumber: new(big.Int).SetUint64(postBlockNum),
OutputRoot: post.Value,
}
return creator(ctx, localContext, agreed, claimed)
}
}
func createLocalContext(pre types.Claim, post types.Claim) common.Hash {
return crypto.Keccak256Hash(localContextPreimage(pre, post))
}
func localContextPreimage(pre types.Claim, post types.Claim) []byte {
encodeClaim := func(c types.Claim) []byte {
data := make([]byte, 64)
copy(data[0:32], c.Value.Bytes())
c.Position.ToGIndex().FillBytes(data[32:])
return data
}
var data []byte
if pre != (types.Claim{}) {
data = encodeClaim(pre)
}
data = append(data, encodeClaim(post)...)
return data
}
package outputs
import (
"context"
"errors"
"math"
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/split"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
var creatorError = errors.New("captured args")
func TestOutputRootSplitAdapter(t *testing.T) {
tests := []struct {
name string
preTraceIndex int64
postTraceIndex int64
expectedAgreedBlockNum int64
expectedClaimedBlockNum int64
}{
{
name: "middleOfBlockRange",
preTraceIndex: 5,
postTraceIndex: 9,
expectedAgreedBlockNum: 26,
expectedClaimedBlockNum: 30,
},
{
name: "beyondPostBlock",
preTraceIndex: 5,
postTraceIndex: 50,
expectedAgreedBlockNum: 26,
expectedClaimedBlockNum: 40,
},
{
name: "firstBlock",
preTraceIndex: 0,
postTraceIndex: 1,
expectedAgreedBlockNum: 21,
expectedClaimedBlockNum: 22,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
topDepth := 10
adapter, creator := setupAdapterTest(t, topDepth)
preClaim := types.Claim{
ClaimData: types.ClaimData{
Value: common.Hash{0xaa},
Position: types.NewPosition(topDepth, big.NewInt(test.preTraceIndex)),
},
ContractIndex: 3,
ParentContractIndex: 2,
}
postClaim := types.Claim{
ClaimData: types.ClaimData{
Value: common.Hash{0xbb},
Position: types.NewPosition(topDepth, big.NewInt(test.postTraceIndex)),
},
ContractIndex: 7,
ParentContractIndex: 1,
}
expectedAgreed := contracts.Proposal{
L2BlockNumber: big.NewInt(test.expectedAgreedBlockNum),
OutputRoot: preClaim.Value,
}
expectedClaimed := contracts.Proposal{
L2BlockNumber: big.NewInt(test.expectedClaimedBlockNum),
OutputRoot: postClaim.Value,
}
_, err := adapter(context.Background(), preClaim, postClaim)
require.ErrorIs(t, err, creatorError)
require.Equal(t, createLocalContext(preClaim, postClaim), creator.localContext)
require.Equal(t, expectedAgreed, creator.agreed)
require.Equal(t, expectedClaimed, creator.claimed)
})
}
}
func TestOutputRootSplitAdapter_FromAbsolutePrestate(t *testing.T) {
topDepth := 10
adapter, creator := setupAdapterTest(t, topDepth)
postClaim := types.Claim{
ClaimData: types.ClaimData{
Value: common.Hash{0xbb},
Position: types.NewPosition(topDepth, big.NewInt(0)),
},
ContractIndex: 7,
ParentContractIndex: 1,
}
expectedAgreed := contracts.Proposal{
L2BlockNumber: big.NewInt(20),
OutputRoot: prestateOutputRoot, // Absolute prestate output root
}
expectedClaimed := contracts.Proposal{
L2BlockNumber: big.NewInt(21),
OutputRoot: postClaim.Value,
}
_, err := adapter(context.Background(), types.Claim{}, postClaim)
require.ErrorIs(t, err, creatorError)
require.Equal(t, createLocalContext(types.Claim{}, postClaim), creator.localContext)
require.Equal(t, expectedAgreed, creator.agreed)
require.Equal(t, expectedClaimed, creator.claimed)
}
func setupAdapterTest(t *testing.T, topDepth int) (split.ProviderCreator, *capturingCreator) {
prestateBlock := uint64(20)
poststateBlock := uint64(40)
creator := &capturingCreator{}
rollupClient := &stubRollupClient{
outputs: map[uint64]*eth.OutputResponse{
prestateBlock: {
OutputRoot: eth.Bytes32(prestateOutputRoot),
},
},
}
topProvider := NewTraceProviderFromInputs(testlog.Logger(t, log.LvlInfo), rollupClient, uint64(topDepth), prestateBlock, poststateBlock)
adapter := OutputRootSplitAdapter(topProvider, creator.Create)
return adapter, creator
}
type capturingCreator struct {
localContext common.Hash
agreed contracts.Proposal
claimed contracts.Proposal
}
func (c *capturingCreator) Create(_ context.Context, localContext common.Hash, agreed contracts.Proposal, claimed contracts.Proposal) (types.TraceProvider, error) {
c.localContext = localContext
c.agreed = agreed
c.claimed = claimed
return nil, creatorError
}
func TestCreateLocalContext(t *testing.T) {
tests := []struct {
name string
preValue common.Hash
prePosition types.Position
postValue common.Hash
postPosition types.Position
expected []byte
}{
{
name: "PreAndPost",
preValue: common.HexToHash("abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"),
prePosition: types.NewPositionFromGIndex(big.NewInt(2)),
postValue: common.HexToHash("cc00000000000000000000000000000000000000000000000000000000000000"),
postPosition: types.NewPositionFromGIndex(big.NewInt(3)),
expected: common.Hex2Bytes("abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234567890000000000000000000000000000000000000000000000000000000000000002cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003"),
},
{
name: "LargePositions",
preValue: common.HexToHash("abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"),
prePosition: types.NewPositionFromGIndex(new(big.Int).SetBytes(common.Hex2Bytes("cbcdef0123456789abcdef0123456789abcdef0123456789abcdef012345678c"))),
postValue: common.HexToHash("dd00000000000000000000000000000000000000000000000000000000000000"),
postPosition: types.NewPositionFromGIndex(new(big.Int).SetUint64(math.MaxUint64)),
expected: common.Hex2Bytes("abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789cbcdef0123456789abcdef0123456789abcdef0123456789abcdef012345678cdd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff"),
},
{
name: "AbsolutePreState",
preValue: common.Hash{},
prePosition: types.Position{},
postValue: common.HexToHash("cc00000000000000000000000000000000000000000000000000000000000000"),
postPosition: types.NewPositionFromGIndex(big.NewInt(3)),
expected: common.Hex2Bytes("cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003"),
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
pre := types.Claim{
ClaimData: types.ClaimData{
Value: test.preValue,
Position: test.prePosition,
},
}
post := types.Claim{
ClaimData: types.ClaimData{
Value: test.postValue,
Position: test.postPosition,
},
}
actualPreimage := localContextPreimage(pre, post)
require.Equal(t, test.expected, actualPreimage)
localContext := createLocalContext(pre, post)
require.Equal(t, crypto.Keccak256Hash(test.expected), localContext)
})
}
}
package outputs package split
import ( import (
"context" "context"
...@@ -16,7 +16,7 @@ var ( ...@@ -16,7 +16,7 @@ var (
type ProviderCreator func(ctx context.Context, pre types.Claim, post types.Claim) (types.TraceProvider, error) type ProviderCreator func(ctx context.Context, pre types.Claim, post types.Claim) (types.TraceProvider, error)
func newSplitProviderSelector(topProvider types.TraceProvider, topDepth int, bottomProviderCreator ProviderCreator) trace.ProviderSelector { func NewSplitProviderSelector(topProvider types.TraceProvider, topDepth int, bottomProviderCreator ProviderCreator) trace.ProviderSelector {
return func(ctx context.Context, game types.Game, ref types.Claim, pos types.Position) (types.TraceProvider, error) { return func(ctx context.Context, game types.Game, ref types.Claim, pos types.Position) (types.TraceProvider, error) {
if pos.Depth() <= topDepth { if pos.Depth() <= topDepth {
return topProvider, nil return topProvider, nil
......
package outputs package split
import ( import (
"context" "context"
...@@ -311,7 +311,7 @@ func setupAlphabetSplitSelector(t *testing.T) (*alphabet.AlphabetTraceProvider, ...@@ -311,7 +311,7 @@ func setupAlphabetSplitSelector(t *testing.T) (*alphabet.AlphabetTraceProvider,
AlphabetTraceProvider: alphabet.NewTraceProvider(post.Value.Hex(), bottomDepth), AlphabetTraceProvider: alphabet.NewTraceProvider(post.Value.Hex(), bottomDepth),
}, nil }, nil
} }
selector := newSplitProviderSelector(top, topDepth, bottomCreator) selector := NewSplitProviderSelector(top, topDepth, bottomCreator)
claimBuilder := test.NewAlphabetClaimBuilder(t, topDepth+bottomDepth) claimBuilder := test.NewAlphabetClaimBuilder(t, topDepth+bottomDepth)
gameBuilder := claimBuilder.GameBuilder(true, true) gameBuilder := claimBuilder.GameBuilder(true, true)
......
...@@ -10,13 +10,17 @@ import ( ...@@ -10,13 +10,17 @@ import (
var ( var (
ErrGameDepthReached = errors.New("game depth reached") ErrGameDepthReached = errors.New("game depth reached")
// NoLocalContext is the LocalContext value used when the cannon trace provider is used alone instead of as part
// of a split game.
NoLocalContext = common.Hash{}
) )
// PreimageOracleData encapsulates the preimage oracle data // PreimageOracleData encapsulates the preimage oracle data
// to load into the onchain oracle. // to load into the onchain oracle.
type PreimageOracleData struct { type PreimageOracleData struct {
IsLocal bool IsLocal bool
LocalContext uint64 LocalContext common.Hash
OracleKey []byte OracleKey []byte
OracleData []byte OracleData []byte
OracleOffset uint32 OracleOffset uint32
...@@ -33,7 +37,7 @@ func (p *PreimageOracleData) GetPreimageWithoutSize() []byte { ...@@ -33,7 +37,7 @@ func (p *PreimageOracleData) GetPreimageWithoutSize() []byte {
} }
// NewPreimageOracleData creates a new [PreimageOracleData] instance. // NewPreimageOracleData creates a new [PreimageOracleData] instance.
func NewPreimageOracleData(lctx uint64, key []byte, data []byte, offset uint32) *PreimageOracleData { func NewPreimageOracleData(lctx common.Hash, key []byte, data []byte, offset uint32) *PreimageOracleData {
return &PreimageOracleData{ return &PreimageOracleData{
IsLocal: len(key) > 0 && key[0] == byte(1), IsLocal: len(key) > 0 && key[0] == byte(1),
LocalContext: lctx, LocalContext: lctx,
......
...@@ -4,23 +4,24 @@ import ( ...@@ -4,23 +4,24 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestNewPreimageOracleData(t *testing.T) { func TestNewPreimageOracleData(t *testing.T) {
t.Run("LocalData", func(t *testing.T) { t.Run("LocalData", func(t *testing.T) {
data := NewPreimageOracleData(1, []byte{1, 2, 3}, []byte{4, 5, 6}, 7) data := NewPreimageOracleData(common.Hash{0x01}, []byte{1, 2, 3}, []byte{4, 5, 6}, 7)
require.True(t, data.IsLocal) require.True(t, data.IsLocal)
require.Equal(t, uint64(1), data.LocalContext) require.Equal(t, common.Hash{0x01}, data.LocalContext)
require.Equal(t, []byte{1, 2, 3}, data.OracleKey) require.Equal(t, []byte{1, 2, 3}, data.OracleKey)
require.Equal(t, []byte{4, 5, 6}, data.OracleData) require.Equal(t, []byte{4, 5, 6}, data.OracleData)
require.Equal(t, uint32(7), data.OracleOffset) require.Equal(t, uint32(7), data.OracleOffset)
}) })
t.Run("GlobalData", func(t *testing.T) { t.Run("GlobalData", func(t *testing.T) {
data := NewPreimageOracleData(1, []byte{0, 2, 3}, []byte{4, 5, 6}, 7) data := NewPreimageOracleData(common.Hash{0x01}, []byte{0, 2, 3}, []byte{4, 5, 6}, 7)
require.False(t, data.IsLocal) require.False(t, data.IsLocal)
require.Equal(t, uint64(1), data.LocalContext) require.Equal(t, common.Hash{0x01}, data.LocalContext)
require.Equal(t, []byte{0, 2, 3}, data.OracleKey) require.Equal(t, []byte{0, 2, 3}, data.OracleKey)
require.Equal(t, []byte{4, 5, 6}, data.OracleData) require.Equal(t, []byte{4, 5, 6}, data.OracleData)
require.Equal(t, uint32(7), data.OracleOffset) require.Equal(t, uint32(7), data.OracleOffset)
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/cannon" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/cannon"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
...@@ -46,7 +47,7 @@ func (g *CannonGameHelper) CreateHonestActor(ctx context.Context, rollupCfg *rol ...@@ -46,7 +47,7 @@ func (g *CannonGameHelper) CreateHonestActor(ctx context.Context, rollupCfg *rol
maxDepth := g.MaxDepth(ctx) maxDepth := g.MaxDepth(ctx)
gameContract, err := contracts.NewFaultDisputeGameContract(g.addr, batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize)) gameContract, err := contracts.NewFaultDisputeGameContract(g.addr, batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize))
g.require.NoError(err, "Create game contract bindings") g.require.NoError(err, "Create game contract bindings")
provider, err := cannon.NewTraceProvider(ctx, logger, metrics.NoopMetrics, cfg, gameContract, cannon.NoLocalContext, filepath.Join(cfg.Datadir, "honest"), uint64(maxDepth)) provider, err := cannon.NewTraceProvider(ctx, logger, metrics.NoopMetrics, cfg, gameContract, types.NoLocalContext, filepath.Join(cfg.Datadir, "honest"), uint64(maxDepth))
g.require.NoError(err, "create cannon trace provider") g.require.NoError(err, "create cannon trace provider")
return &HonestHelper{ return &HonestHelper{
......
...@@ -225,7 +225,7 @@ func (h *FactoryHelper) StartCannonGameWithCorrectRoot(ctx context.Context, roll ...@@ -225,7 +225,7 @@ func (h *FactoryHelper) StartCannonGameWithCorrectRoot(ctx context.Context, roll
testlog.Logger(h.t, log.LvlInfo).New("role", "CorrectTrace"), testlog.Logger(h.t, log.LvlInfo).New("role", "CorrectTrace"),
metrics.NoopMetrics, metrics.NoopMetrics,
cfg, cfg,
cannon.NoLocalContext, faultTypes.NoLocalContext,
inputs, inputs,
cfg.Datadir, cfg.Datadir,
maxDepth.Uint64(), maxDepth.Uint64(),
......
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