From af021ee8481bb6adf6715c81ff0c062f04f2f03a Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 29 Aug 2024 12:48:56 +0200 Subject: [PATCH 01/31] wip --- bridgesync/claimcalldata_test.go | 33 +++++++++++++++ bridgesync/docker-compose.yml | 26 ++++++++++++ bridgesync/downloader.go | 26 ++++++++++++ bridgesync/processor.go | 14 ++++--- test/contracts/bind.sh | 3 +- test/contracts/claimmock/ClaimMock.sol | 57 ++++++++++++++++++++++++++ tree/appendonlytree.go | 10 ++--- tree/tree.go | 16 ++++---- tree/updatabletree.go | 6 +-- 9 files changed, 169 insertions(+), 22 deletions(-) create mode 100644 bridgesync/claimcalldata_test.go create mode 100644 bridgesync/docker-compose.yml create mode 100644 test/contracts/claimmock/ClaimMock.sol diff --git a/bridgesync/claimcalldata_test.go b/bridgesync/claimcalldata_test.go new file mode 100644 index 00000000..2e30b908 --- /dev/null +++ b/bridgesync/claimcalldata_test.go @@ -0,0 +1,33 @@ +package bridgesync + +import ( + "math/big" + "os/exec" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/stretchr/testify/require" +) + +func newDockerBackend(t *testing.T) { + msg, err := exec.Command("bash", "-l", "-c", "docker compose up -d test-claimcalldata-l1").CombinedOutput() + require.NoError(t, err, string(msg)) +} + +func TestClaimCalldata(t *testing.T) { + msg, err := exec.Command("bash", "-l", "-c", "docker compose up -d").CombinedOutput() + require.NoError(t, err, string(msg)) + defer func() { + msg, err = exec.Command("bash", "-l", "-c", "docker compose down").CombinedOutput() + require.NoError(t, err, string(msg)) + }() + client, err := ethclient.Dial("http://localhost:8545") + require.NoError(t, err) + privateKey, err := crypto.HexToECDSA("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") + require.NoError(t, err) + auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(0).SetUint64(1337)) + require.NoError(t, err) + +} diff --git a/bridgesync/docker-compose.yml b/bridgesync/docker-compose.yml new file mode 100644 index 00000000..b09a1e4a --- /dev/null +++ b/bridgesync/docker-compose.yml @@ -0,0 +1,26 @@ +networks: + default: + name: test-claimdata + +services: + test-claimdata-l1: + container_name: test-claimdata-l1 + image: hermeznetwork/geth-zkevm-contracts:elderberry-fork.9-geth1.13.11 + environment: + - DEV_PERIOD + ports: + - "8545:8545" + entrypoint: + - geth + - --http + - --http.addr + - "0.0.0.0" + - "--http.corsdomain" + - "*" + - "--http.vhosts" + - "*" + - --dev + - --dev.period + - "1" + - "--datadir" + - "/geth_data" diff --git a/bridgesync/downloader.go b/bridgesync/downloader.go index 9ed031b5..93ca69ad 100644 --- a/bridgesync/downloader.go +++ b/bridgesync/downloader.go @@ -1,17 +1,22 @@ package bridgesync import ( + "context" "fmt" "math/big" "github.com/0xPolygon/cdk-contracts-tooling/contracts/etrog/polygonzkevmbridge" "github.com/0xPolygon/cdk-contracts-tooling/contracts/etrog/polygonzkevmbridgev2" + "github.com/0xPolygon/cdk/log" "github.com/0xPolygon/cdk/sync" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" ) var ( @@ -97,3 +102,24 @@ func buildAppender(client EthClienter, bridge common.Address) (sync.LogAppenderM return appender, nil } + +type fixedClient struct { + *ethclient.Client +} + +func (c *fixedClient) BlockByNumber(context.Context, rpc.BlockNumber) (*types.Block, error) { + return nil, nil +} + +func setClaimCalldata(ctx context.Context, client *ethclient.Client, txHash common.Hash, claim *Claim) error { + tracer := tracers.NewAPI(client) + tracerType := "callTracer" + trace, err := tracer.TraceTransaction(ctx, txHash, &tracers.TraceConfig{Tracer: &tracerType}) + if err != nil { + return err + } + log.Debug(trace) + return nil +} + +func decodeClaimCall(data []byte) {} diff --git a/bridgesync/processor.go b/bridgesync/processor.go index b8e15e52..5b319e73 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -69,11 +69,15 @@ func (b *Bridge) Hash() common.Hash { // Claim representation of a claim event type Claim struct { - GlobalIndex *big.Int - OriginNetwork uint32 - OriginAddress common.Address - DestinationAddress common.Address - Amount *big.Int + GlobalIndex *big.Int + OriginNetwork uint32 + OriginAddress common.Address + DestinationAddress common.Address + Amount *big.Int + ProofLocalExitRoot [tree.DefaultHeight]common.Hash + ProofRollupExitRoot [tree.DefaultHeight]common.Hash + MainnetExitRoot common.Hash + RollupExitRoot common.Hash } // Event combination of bridge and claim events diff --git a/test/contracts/bind.sh b/test/contracts/bind.sh index f0150d16..79cbbc39 100755 --- a/test/contracts/bind.sh +++ b/test/contracts/bind.sh @@ -8,4 +8,5 @@ gen() { abigen --bin bin/${package}.bin --abi abi/${package}.abi --pkg=${package} --out=${package}/${package}.go } -gen verifybatchesmock \ No newline at end of file +gen verifybatchesmock +gen claimmock \ No newline at end of file diff --git a/test/contracts/claimmock/ClaimMock.sol b/test/contracts/claimmock/ClaimMock.sol new file mode 100644 index 00000000..b2a84a04 --- /dev/null +++ b/test/contracts/claimmock/ClaimMock.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: AGPL-3.0 + +pragma solidity 0.8.18; + +contract ClaimMock { + event ClaimEvent( + uint256 globalIndex, + uint32 originNetwork, + address originAddress, + address destinationAddress, + uint256 amount + ); + + function claimAsset( + bytes32[32] calldata smtProofLocalExitRoot, + bytes32[32] calldata smtProofRollupExitRoot, + uint256 globalIndex, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originTokenAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata + ) external { + emit ClaimEvent( + globalIndex, + originNetwork, + originTokenAddress, + destinationAddress, + amount + ); + } + + function claimMessage( + bytes32[32] calldata smtProofLocalExitRoot, + bytes32[32] calldata smtProofRollupExitRoot, + uint256 globalIndex, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata + ) external { + emit ClaimEvent( + globalIndex, + originNetwork, + originAddress, + destinationAddress, + amount + ); + } +} \ No newline at end of file diff --git a/tree/appendonlytree.go b/tree/appendonlytree.go index d04454f1..5b714bfb 100644 --- a/tree/appendonlytree.go +++ b/tree/appendonlytree.go @@ -12,7 +12,7 @@ import ( // AppendOnlyTree is a tree where leaves are added sequentially (by index) type AppendOnlyTree struct { *Tree - lastLeftCache [defaultHeight]common.Hash + lastLeftCache [DefaultHeight]common.Hash lastIndex int64 } @@ -36,7 +36,7 @@ func (t *AppendOnlyTree) AddLeaves(tx kv.RwTx, leaves []Leaf) (func(), error) { } backupIndx := t.lastIndex - backupCache := [defaultHeight]common.Hash{} + backupCache := [DefaultHeight]common.Hash{} copy(backupCache[:], t.lastLeftCache[:]) rollback := func() { t.lastIndex = backupIndx @@ -62,7 +62,7 @@ func (t *AppendOnlyTree) addLeaf(tx kv.RwTx, leaf Leaf) error { // Calculate new tree nodes currentChildHash := leaf.Hash newNodes := []treeNode{} - for h := uint8(0); h < defaultHeight; h++ { + for h := uint8(0); h < DefaultHeight; h++ { var parent treeNode if leaf.Index&(1< 0 { // Add child to the right @@ -155,7 +155,7 @@ func (t *AppendOnlyTree) initLastIndex(tx kv.Tx) (common.Hash, error) { } func (t *AppendOnlyTree) initLastLeftCache(tx kv.Tx, lastIndex int64, lastRoot common.Hash) error { - siblings := [defaultHeight]common.Hash{} + siblings := [DefaultHeight]common.Hash{} if lastIndex == -1 { t.lastLeftCache = siblings return nil @@ -164,7 +164,7 @@ func (t *AppendOnlyTree) initLastLeftCache(tx kv.Tx, lastIndex int64, lastRoot c currentNodeHash := lastRoot // It starts in height-1 because 0 is the level of the leafs - for h := int(defaultHeight - 1); h >= 0; h-- { + for h := int(DefaultHeight - 1); h >= 0; h-- { currentNode, err := t.getRHTNode(tx, currentNodeHash) if err != nil { return fmt.Errorf( diff --git a/tree/tree.go b/tree/tree.go index e7f8e5c1..77c0e452 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -13,7 +13,7 @@ import ( ) const ( - defaultHeight uint8 = 32 + DefaultHeight uint8 = 32 rootTableSufix = "-root" rhtTableSufix = "-rht" indexTableSufix = "-index" @@ -83,7 +83,7 @@ func newTree(db kv.RwDB, dbPrefix string) *Tree { rootTable: rootTable, indexTable: indexTable, db: db, - zeroHashes: generateZeroHashes(defaultHeight), + zeroHashes: generateZeroHashes(DefaultHeight), } return t @@ -118,7 +118,7 @@ func (t *Tree) getSiblings(tx kv.Tx, index uint32, root common.Hash) ( ) { currentNodeHash := root // It starts in height-1 because 0 is the level of the leafs - for h := int(defaultHeight - 1); h >= 0; h-- { + for h := int(DefaultHeight - 1); h >= 0; h-- { var currentNode *treeNode currentNode, err = t.getRHTNode(tx, currentNodeHash) if err != nil { @@ -169,18 +169,18 @@ func (t *Tree) getSiblings(tx kv.Tx, index uint32, root common.Hash) ( } // GetProof returns the merkle proof for a given index and root. -func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) ([defaultHeight]common.Hash, error) { +func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) ([DefaultHeight]common.Hash, error) { tx, err := t.db.BeginRw(ctx) if err != nil { - return [defaultHeight]common.Hash{}, err + return [DefaultHeight]common.Hash{}, err } defer tx.Rollback() siblings, isErrNotFound, err := t.getSiblings(tx, index, root) if err != nil { - return [defaultHeight]common.Hash{}, err + return [DefaultHeight]common.Hash{}, err } if isErrNotFound { - return [defaultHeight]common.Hash{}, ErrNotFound + return [DefaultHeight]common.Hash{}, ErrNotFound } return siblings, nil } @@ -284,7 +284,7 @@ func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (com defer tx.Rollback() currentNodeHash := root - for h := int(defaultHeight - 1); h >= 0; h-- { + for h := int(DefaultHeight - 1); h >= 0; h-- { currentNode, err := t.getRHTNode(tx, currentNodeHash) if err != nil { return common.Hash{}, err diff --git a/tree/updatabletree.go b/tree/updatabletree.go index 48365ee2..5c54deb1 100644 --- a/tree/updatabletree.go +++ b/tree/updatabletree.go @@ -29,7 +29,7 @@ func NewUpdatableTree(ctx context.Context, db kv.RwDB, dbPrefix string) (*Updata return nil, err } if rootIndex == -1 { - root = t.zeroHashes[defaultHeight] + root = t.zeroHashes[DefaultHeight] } ut := &UpdatableTree{ Tree: t, @@ -70,7 +70,7 @@ func (t *UpdatableTree) upsertLeaf(tx kv.RwTx, leaf Leaf) error { } currentChildHash := leaf.Hash newNodes := []treeNode{} - for h := uint8(0); h < defaultHeight; h++ { + for h := uint8(0); h < DefaultHeight; h++ { var parent treeNode if leaf.Index&(1< 0 { // Add child to the right @@ -130,7 +130,7 @@ func (t *UpdatableTree) Reorg(tx kv.RwTx, firstReorgedIndex uint64) (func(), err } // no root found after reorg, going back to empty tree - t.lastRoot = t.zeroHashes[defaultHeight] + t.lastRoot = t.zeroHashes[DefaultHeight] return rollback, nil } From f80e900d39b995336848dd235fd78a4509b79f2d Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 29 Aug 2024 12:49:37 +0200 Subject: [PATCH 02/31] wip --- bridgesync/downloader.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/bridgesync/downloader.go b/bridgesync/downloader.go index 93ca69ad..6ae76914 100644 --- a/bridgesync/downloader.go +++ b/bridgesync/downloader.go @@ -16,7 +16,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" ) var ( @@ -103,14 +102,6 @@ func buildAppender(client EthClienter, bridge common.Address) (sync.LogAppenderM return appender, nil } -type fixedClient struct { - *ethclient.Client -} - -func (c *fixedClient) BlockByNumber(context.Context, rpc.BlockNumber) (*types.Block, error) { - return nil, nil -} - func setClaimCalldata(ctx context.Context, client *ethclient.Client, txHash common.Hash, claim *Claim) error { tracer := tracers.NewAPI(client) tracerType := "callTracer" From cace93273aa03df1e27b1b69d319ae4927fbbd00 Mon Sep 17 00:00:00 2001 From: bros Date: Thu, 29 Aug 2024 17:26:25 +0000 Subject: [PATCH 03/31] WIP --- bridgesync/claimcalldata_test.go | 103 ++++- bridgesync/docker-compose.yml | 2 + bridgesync/downloader.go | 122 +++++- go.mod | 1 + go.sum | 2 + test/contracts/ClaimMock.abi | 1 + test/contracts/ClaimMock.bin | 1 + test/contracts/abi/claimmock.abi | 165 ++++++++ test/contracts/abi/claimmockcaller.abi | 152 +++++++ test/contracts/bin/claimmock.bin | 1 + test/contracts/bin/claimmockcaller.bin | 1 + test/contracts/bind.sh | 3 +- test/contracts/claimmock/ClaimMock.sol | 12 +- test/contracts/claimmock/claimmock.go | 383 ++++++++++++++++++ .../claimmockcaller/ClaimMockCaller.sol | 76 ++++ .../claimmockcaller/claimmockcaller.go | 276 +++++++++++++ 16 files changed, 1280 insertions(+), 21 deletions(-) create mode 100644 test/contracts/ClaimMock.abi create mode 100644 test/contracts/ClaimMock.bin create mode 100644 test/contracts/abi/claimmock.abi create mode 100644 test/contracts/abi/claimmockcaller.abi create mode 100644 test/contracts/bin/claimmock.bin create mode 100644 test/contracts/bin/claimmockcaller.bin create mode 100644 test/contracts/claimmock/claimmock.go create mode 100644 test/contracts/claimmockcaller/ClaimMockCaller.sol create mode 100644 test/contracts/claimmockcaller/claimmockcaller.go diff --git a/bridgesync/claimcalldata_test.go b/bridgesync/claimcalldata_test.go index 2e30b908..17e7db5a 100644 --- a/bridgesync/claimcalldata_test.go +++ b/bridgesync/claimcalldata_test.go @@ -1,24 +1,27 @@ package bridgesync import ( + "context" "math/big" "os/exec" "testing" + "time" + "github.com/0xPolygon/cdk/test/contracts/claimmock" + "github.com/0xPolygon/cdk/test/contracts/claimmockcaller" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/stretchr/testify/require" ) -func newDockerBackend(t *testing.T) { - msg, err := exec.Command("bash", "-l", "-c", "docker compose up -d test-claimcalldata-l1").CombinedOutput() - require.NoError(t, err, string(msg)) -} - func TestClaimCalldata(t *testing.T) { + // Setup Docker L1 + ctx := context.Background() msg, err := exec.Command("bash", "-l", "-c", "docker compose up -d").CombinedOutput() require.NoError(t, err, string(msg)) + time.Sleep(time.Second * 5) defer func() { msg, err = exec.Command("bash", "-l", "-c", "docker compose down").CombinedOutput() require.NoError(t, err, string(msg)) @@ -30,4 +33,94 @@ func TestClaimCalldata(t *testing.T) { auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(0).SetUint64(1337)) require.NoError(t, err) + // Deploy contracts + bridgeAddr, _, bridgeContract, err := claimmock.DeployClaimmock(auth, client) + require.NoError(t, err) + _, _, claimCaller, err := claimmockcaller.DeployClaimmockcaller(auth, client, bridgeAddr) + require.NoError(t, err) + + proofLocal := [32][32]byte{} + proofLocalH := [32]common.Hash{} + proofLocal[5] = common.HexToHash("beef") + proofLocalH[5] = common.HexToHash("beef") + proofRollup := [32][32]byte{} + proofRollupH := [32]common.Hash{} + proofRollup[4] = common.HexToHash("a1fa") + proofRollupH[4] = common.HexToHash("a1fa") + expectedClaim := Claim{ + GlobalIndex: big.NewInt(420), + OriginNetwork: 69, + OriginAddress: common.HexToAddress("ffaaffaa"), + DestinationAddress: common.HexToAddress("123456789"), + Amount: big.NewInt(3), + MainnetExitRoot: common.HexToHash("5ca1e"), + RollupExitRoot: common.HexToHash("dead"), + ProofLocalExitRoot: proofLocalH, + ProofRollupExitRoot: proofRollupH, + } + auth.GasLimit = 999999 + + // direct call + tx, err := bridgeContract.ClaimAsset( + auth, + proofLocal, + proofRollup, + expectedClaim.GlobalIndex, + expectedClaim.MainnetExitRoot, + expectedClaim.RollupExitRoot, + expectedClaim.OriginNetwork, + expectedClaim.OriginAddress, + 0, + expectedClaim.DestinationAddress, + expectedClaim.Amount, + nil, + ) + require.NoError(t, err) + time.Sleep(2 * time.Second) + r, err := client.TransactionReceipt(ctx, tx.Hash()) + require.NoError(t, err) + claimEvent, err := bridgeContract.ParseClaimEvent(*r.Logs[0]) + require.NoError(t, err) + actualClaim := Claim{ + GlobalIndex: claimEvent.GlobalIndex, + OriginNetwork: claimEvent.OriginNetwork, + OriginAddress: claimEvent.OriginAddress, + DestinationAddress: claimEvent.DestinationAddress, + Amount: claimEvent.Amount, + } + err = setClaimCalldata(client, bridgeAddr, tx.Hash(), &actualClaim) + require.NoError(t, err) + require.Equal(t, expectedClaim, actualClaim) + + // indirect call + tx, err = claimCaller.ClaimAsset( + auth, + proofLocal, + proofRollup, + expectedClaim.GlobalIndex, + expectedClaim.MainnetExitRoot, + expectedClaim.RollupExitRoot, + expectedClaim.OriginNetwork, + expectedClaim.OriginAddress, + 0, + expectedClaim.DestinationAddress, + expectedClaim.Amount, + nil, + ) + require.NoError(t, err) + time.Sleep(2 * time.Second) + r, err = client.TransactionReceipt(ctx, tx.Hash()) + require.NoError(t, err) + claimEvent, err = bridgeContract.ParseClaimEvent(*r.Logs[0]) + require.NoError(t, err) + actualClaim = Claim{ + GlobalIndex: claimEvent.GlobalIndex, + OriginNetwork: claimEvent.OriginNetwork, + OriginAddress: claimEvent.OriginAddress, + DestinationAddress: claimEvent.DestinationAddress, + Amount: claimEvent.Amount, + } + err = setClaimCalldata(client, bridgeAddr, tx.Hash(), &actualClaim) + require.NoError(t, err) + require.Equal(t, expectedClaim, actualClaim) } diff --git a/bridgesync/docker-compose.yml b/bridgesync/docker-compose.yml index b09a1e4a..701bfb8a 100644 --- a/bridgesync/docker-compose.yml +++ b/bridgesync/docker-compose.yml @@ -24,3 +24,5 @@ services: - "1" - "--datadir" - "/geth_data" + - "--http.api" + - "admin,eth,debug,miner,net,txpool,personal,web3" diff --git a/bridgesync/downloader.go b/bridgesync/downloader.go index 6ae76914..59ea1157 100644 --- a/bridgesync/downloader.go +++ b/bridgesync/downloader.go @@ -1,27 +1,31 @@ package bridgesync import ( - "context" + "bytes" "fmt" "math/big" + "strings" "github.com/0xPolygon/cdk-contracts-tooling/contracts/etrog/polygonzkevmbridge" "github.com/0xPolygon/cdk-contracts-tooling/contracts/etrog/polygonzkevmbridgev2" - "github.com/0xPolygon/cdk/log" + rpcTypes "github.com/0xPolygon/cdk-rpc/types" "github.com/0xPolygon/cdk/sync" + "github.com/0xPolygon/cdk/tree" "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethclient" + "github.com/golang-collections/collections/stack" ) var ( bridgeEventSignature = crypto.Keccak256Hash([]byte("BridgeEvent(uint8,uint32,address,uint32,address,uint256,bytes,uint32)")) claimEventSignature = crypto.Keccak256Hash([]byte("ClaimEvent(uint256,uint32,address,address,uint256)")) claimEventSignaturePreEtrog = crypto.Keccak256Hash([]byte("ClaimEvent(uint32,uint32,address,address,uint256)")) + methodIDClaimAsset = common.Hex2Bytes("ccaa2d11") ) type EthClienter interface { @@ -102,15 +106,113 @@ func buildAppender(client EthClienter, bridge common.Address) (sync.LogAppenderM return appender, nil } -func setClaimCalldata(ctx context.Context, client *ethclient.Client, txHash common.Hash, claim *Claim) error { - tracer := tracers.NewAPI(client) - tracerType := "callTracer" - trace, err := tracer.TraceTransaction(ctx, txHash, &tracers.TraceConfig{Tracer: &tracerType}) +type call struct { + To common.Address `json:"to"` + Value *rpcTypes.ArgBig `json:"value"` + // Err *string `json:"error"` + Input rpcTypes.ArgBytes `json:"input"` + Calls []call `json:"calls"` +} + +type tracerCfg struct { + Tracer string `json:"tracer"` +} + +func setClaimCalldata(client *ethclient.Client, bridgeAddr common.Address, txHash common.Hash, claim *Claim) error { + c := &call{} + err := client.Client().Call(c, "debug_traceTransaction", txHash, tracerCfg{Tracer: "callTracer"}) if err != nil { return err } - log.Debug(trace) - return nil + + // find the claim linked to the event using DFS + // TODO: take into account potential reverts that may be found on the path, + // and other edge cases + callStack := stack.New() + callStack.Push(*c) + for { + if callStack.Len() == 0 { + break + } + currentCall := callStack.Pop().(call) + if currentCall.To == bridgeAddr { + found, err := setClaimIfFoundOnInput( + currentCall.Input, + claim, + ) + if err != nil { + return err + } + if found { + return nil + } + } + for _, c := range currentCall.Calls { + callStack.Push(c) + } + } + return ErrNotFound } -func decodeClaimCall(data []byte) {} +func setClaimIfFoundOnInput(input []byte, claim *Claim) (bool, error) { + smcAbi, err := abi.JSON(strings.NewReader(polygonzkevmbridgev2.Polygonzkevmbridgev2ABI)) + if err != nil { + return false, err + } + methodId := input[:4] + + // Ignore other methods + if !bytes.Equal(methodId, methodIDClaimAsset) { + return false, nil + } + + // Recover Method from signature and ABI + method, err := smcAbi.MethodById(methodId) + if err != nil { + return false, err + } + + /* Unpack method inputs + claimAsset( + 0: smtProofLocalExitRoot, + 1: smtProofRollupExitRoot, + 2: globalIndex, + 3: mainnetExitRoot, + 4: rollupExitRoot, + 5: originNetwork, + 6: originTokenAddress, + 7: destinationNetwork, + 8: destinationAddress, + 9: amount, + 10: metadata, + ) + */ + data, err := method.Inputs.Unpack(input[4:]) + if err != nil { + return false, err + } + + // TODO: support both claim asset & message, check if previous versions need special treatment + // TODO: ignore claim messages that don't have value + actualGlobalIndex := data[2].(*big.Int) + if actualGlobalIndex.Cmp(claim.GlobalIndex) != 0 { + // not the claim we're looking for + return false, nil + } else { + proofLER := [tree.DefaultHeight]common.Hash{} + proofLERBytes := data[0].([32][32]byte) + proofRER := [tree.DefaultHeight]common.Hash{} + proofRERBytes := data[1].([32][32]byte) + for i := 0; i < int(tree.DefaultHeight); i++ { + proofLER[i] = proofLERBytes[i] + proofRER[i] = proofRERBytes[i] + } + // TODO: add ALL the data, hard to know what we're gonna need in the future + claim.ProofLocalExitRoot = proofLER + claim.ProofRollupExitRoot = proofRER + claim.MainnetExitRoot = data[3].([32]byte) + claim.RollupExitRoot = data[4].([32]byte) + claim.Amount = data[9].(*big.Int) + return true, nil + } +} diff --git a/go.mod b/go.mod index eb37abe8..940ce107 100644 --- a/go.mod +++ b/go.mod @@ -72,6 +72,7 @@ require ( github.com/go-stack/stack v1.8.1 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/uuid v1.6.0 // indirect diff --git a/go.sum b/go.sum index cb93abd1..bd4c8857 100644 --- a/go.sum +++ b/go.sum @@ -139,6 +139,8 @@ github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPh github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4= +github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= diff --git a/test/contracts/ClaimMock.abi b/test/contracts/ClaimMock.abi new file mode 100644 index 00000000..d439c7f6 --- /dev/null +++ b/test/contracts/ClaimMock.abi @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"globalIndex","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"originNetwork","type":"uint32"},{"indexed":false,"internalType":"address","name":"originAddress","type":"address"},{"indexed":false,"internalType":"address","name":"destinationAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimEvent","type":"event"},{"inputs":[{"internalType":"uint256","name":"globalIndex","type":"uint256"},{"internalType":"uint32","name":"originNetwork","type":"uint32"},{"internalType":"address","name":"originTokenAddress","type":"address"},{"internalType":"address","name":"destinationAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claimAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"globalIndex","type":"uint256"},{"internalType":"uint32","name":"originNetwork","type":"uint32"},{"internalType":"address","name":"originAddress","type":"address"},{"internalType":"address","name":"destinationAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claimMessage","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/test/contracts/ClaimMock.bin b/test/contracts/ClaimMock.bin new file mode 100644 index 00000000..522d1126 --- /dev/null +++ b/test/contracts/ClaimMock.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50610305806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636f027e4c1461003b57806392b5670b14610057575b600080fd5b610055600480360381019061005091906101d4565b610073565b005b610071600480360381019061006c91906101d4565b6100b9565b005b7f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d85858585856040516100aa95949392919061027c565b60405180910390a15050505050565b7f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d85858585856040516100f095949392919061027c565b60405180910390a15050505050565b600080fd5b6000819050919050565b61011781610104565b811461012257600080fd5b50565b6000813590506101348161010e565b92915050565b600063ffffffff82169050919050565b6101538161013a565b811461015e57600080fd5b50565b6000813590506101708161014a565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101a182610176565b9050919050565b6101b181610196565b81146101bc57600080fd5b50565b6000813590506101ce816101a8565b92915050565b600080600080600060a086880312156101f0576101ef6100ff565b5b60006101fe88828901610125565b955050602061020f88828901610161565b9450506040610220888289016101bf565b9350506060610231888289016101bf565b925050608061024288828901610125565b9150509295509295909350565b61025881610104565b82525050565b6102678161013a565b82525050565b61027681610196565b82525050565b600060a082019050610291600083018861024f565b61029e602083018761025e565b6102ab604083018661026d565b6102b8606083018561026d565b6102c5608083018461024f565b969550505050505056fea26469706673582212202e7016e57820c7c09f82ea7928de88dbf547057550cdf9e081466bdeb58198b664736f6c63430008120033 \ No newline at end of file diff --git a/test/contracts/abi/claimmock.abi b/test/contracts/abi/claimmock.abi new file mode 100644 index 00000000..e7a51225 --- /dev/null +++ b/test/contracts/abi/claimmock.abi @@ -0,0 +1,165 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "globalIndex", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "originNetwork", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "address", + "name": "originAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "destinationAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ClaimEvent", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "bytes32[32]", + "name": "smtProofLocalExitRoot", + "type": "bytes32[32]" + }, + { + "internalType": "bytes32[32]", + "name": "smtProofRollupExitRoot", + "type": "bytes32[32]" + }, + { + "internalType": "uint256", + "name": "globalIndex", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "mainnetExitRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "rollupExitRoot", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "originNetwork", + "type": "uint32" + }, + { + "internalType": "address", + "name": "originTokenAddress", + "type": "address" + }, + { + "internalType": "uint32", + "name": "destinationNetwork", + "type": "uint32" + }, + { + "internalType": "address", + "name": "destinationAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "name": "claimAsset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[32]", + "name": "smtProofLocalExitRoot", + "type": "bytes32[32]" + }, + { + "internalType": "bytes32[32]", + "name": "smtProofRollupExitRoot", + "type": "bytes32[32]" + }, + { + "internalType": "uint256", + "name": "globalIndex", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "mainnetExitRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "rollupExitRoot", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "originNetwork", + "type": "uint32" + }, + { + "internalType": "address", + "name": "originAddress", + "type": "address" + }, + { + "internalType": "uint32", + "name": "destinationNetwork", + "type": "uint32" + }, + { + "internalType": "address", + "name": "destinationAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "name": "claimMessage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] \ No newline at end of file diff --git a/test/contracts/abi/claimmockcaller.abi b/test/contracts/abi/claimmockcaller.abi new file mode 100644 index 00000000..35244b7d --- /dev/null +++ b/test/contracts/abi/claimmockcaller.abi @@ -0,0 +1,152 @@ +[ + { + "inputs": [ + { + "internalType": "contract IClaimMock", + "name": "_claimMock", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "bytes32[32]", + "name": "smtProofLocalExitRoot", + "type": "bytes32[32]" + }, + { + "internalType": "bytes32[32]", + "name": "smtProofRollupExitRoot", + "type": "bytes32[32]" + }, + { + "internalType": "uint256", + "name": "globalIndex", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "mainnetExitRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "rollupExitRoot", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "originNetwork", + "type": "uint32" + }, + { + "internalType": "address", + "name": "originTokenAddress", + "type": "address" + }, + { + "internalType": "uint32", + "name": "destinationNetwork", + "type": "uint32" + }, + { + "internalType": "address", + "name": "destinationAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "name": "claimAsset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[32]", + "name": "smtProofLocalExitRoot", + "type": "bytes32[32]" + }, + { + "internalType": "bytes32[32]", + "name": "smtProofRollupExitRoot", + "type": "bytes32[32]" + }, + { + "internalType": "uint256", + "name": "globalIndex", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "mainnetExitRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "rollupExitRoot", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "originNetwork", + "type": "uint32" + }, + { + "internalType": "address", + "name": "originAddress", + "type": "address" + }, + { + "internalType": "uint32", + "name": "destinationNetwork", + "type": "uint32" + }, + { + "internalType": "address", + "name": "destinationAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "name": "claimMessage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "claimMock", + "outputs": [ + { + "internalType": "contract IClaimMock", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ] \ No newline at end of file diff --git a/test/contracts/bin/claimmock.bin b/test/contracts/bin/claimmock.bin new file mode 100644 index 00000000..bbde9978 --- /dev/null +++ b/test/contracts/bin/claimmock.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b5061025a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063ccaa2d111461003b578063f5efcd791461003b575b600080fd5b61004e61004936600461011c565b610050565b005b604080518b815263ffffffff8916602082015273ffffffffffffffffffffffffffffffffffffffff88811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b8061040081018310156100d957600080fd5b92915050565b803563ffffffff811681146100f357600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146100f357600080fd5b6000806000806000806000806000806000806109208d8f03121561013f57600080fd5b6101498e8e6100c7565b9b506101598e6104008f016100c7565b9a506108008d013599506108208d013598506108408d013597506101806108608e016100df565b965061018f6108808e016100f8565b955061019e6108a08e016100df565b94506101ad6108c08e016100f8565b93506108e08d013592506109008d013567ffffffffffffffff808211156101d357600080fd5b818f0191508f601f8301126101e757600080fd5b80823511156101f557600080fd5b508e60208235830101111561020957600080fd5b60208101925080359150509295989b509295989b509295989b56fea26469706673582212201bdd4081435a27b9ab2f7421c2d1f3979d52c6cece33269bd75823a6e6a7fe2b64736f6c63430008140033 \ No newline at end of file diff --git a/test/contracts/bin/claimmockcaller.bin b/test/contracts/bin/claimmockcaller.bin new file mode 100644 index 00000000..3dad9a9d --- /dev/null +++ b/test/contracts/bin/claimmockcaller.bin @@ -0,0 +1 @@ +60a060405234801561001057600080fd5b5060405161050238038061050283398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b60805161046b61009760003960008181604b0152818160fb01526101c3015261046b6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806383f5b00614610046578063ccaa2d1114610096578063f5efcd79146100ab575b600080fd5b61006d7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100a96100a4366004610263565b6100be565b005b6100a96100b9366004610263565b610186565b6040517fccaa2d1100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063ccaa2d1190610146908f908f908f908f908f908f908f908f908f908f908f908f9060040161036b565b600060405180830381600087803b15801561016057600080fd5b505af1158015610174573d6000803e3d6000fd5b50505050505050505050505050505050565b6040517ff5efcd7900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f5efcd7990610146908f908f908f908f908f908f908f908f908f908f908f908f9060040161036b565b80610400810183101561022057600080fd5b92915050565b803563ffffffff8116811461023a57600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461023a57600080fd5b6000806000806000806000806000806000806109208d8f03121561028657600080fd5b6102908e8e61020e565b9b506102a08e6104008f0161020e565b9a506108008d013599506108208d013598506108408d013597506102c76108608e01610226565b96506102d66108808e0161023f565b95506102e56108a08e01610226565b94506102f46108c08e0161023f565b93506108e08d013592506109008d013567ffffffffffffffff8082111561031a57600080fd5b818f0191508f601f83011261032e57600080fd5b808235111561033c57600080fd5b508e60208235830101111561035057600080fd5b60208101925080359150509295989b509295989b509295989b565b6000610400808f8437808e82850137508b6108008301528a6108208301528961084083015263ffffffff808a1661086084015273ffffffffffffffffffffffffffffffffffffffff808a166108808501528189166108a08501528088166108c08501525050846108e0830152610920610900830152826109208301526109408385828501376000838501820152601f9093017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169091019091019c9b50505050505050505050505056fea26469706673582212206727c3a78a95fb986d1a4568ebb299bd4398120ac4cd67a415f2c5c02e5ee78f64736f6c63430008140033 \ No newline at end of file diff --git a/test/contracts/bind.sh b/test/contracts/bind.sh index 79cbbc39..957fd956 100755 --- a/test/contracts/bind.sh +++ b/test/contracts/bind.sh @@ -9,4 +9,5 @@ gen() { } gen verifybatchesmock -gen claimmock \ No newline at end of file +gen claimmock +gen claimmockcaller \ No newline at end of file diff --git a/test/contracts/claimmock/ClaimMock.sol b/test/contracts/claimmock/ClaimMock.sol index b2a84a04..cb609eae 100644 --- a/test/contracts/claimmock/ClaimMock.sol +++ b/test/contracts/claimmock/ClaimMock.sol @@ -1,8 +1,10 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.18; +pragma solidity 0.8.20; contract ClaimMock { + uint8 constant _DEPOSIT_CONTRACT_TREE_DEPTH = 32; + event ClaimEvent( uint256 globalIndex, uint32 originNetwork, @@ -12,8 +14,8 @@ contract ClaimMock { ); function claimAsset( - bytes32[32] calldata smtProofLocalExitRoot, - bytes32[32] calldata smtProofRollupExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, @@ -34,8 +36,8 @@ contract ClaimMock { } function claimMessage( - bytes32[32] calldata smtProofLocalExitRoot, - bytes32[32] calldata smtProofRollupExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, diff --git a/test/contracts/claimmock/claimmock.go b/test/contracts/claimmock/claimmock.go new file mode 100644 index 00000000..dacd0458 --- /dev/null +++ b/test/contracts/claimmock/claimmock.go @@ -0,0 +1,383 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package claimmock + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// ClaimmockMetaData contains all meta data concerning the Claimmock contract. +var ClaimmockMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"globalIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originNetwork\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ClaimEvent\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofLocalExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofRollupExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"uint256\",\"name\":\"globalIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"mainnetExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"rollupExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"originNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"destinationNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"name\":\"claimAsset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofLocalExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofRollupExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"uint256\",\"name\":\"globalIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"mainnetExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"rollupExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"originNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"destinationNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"name\":\"claimMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b5061025a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063ccaa2d111461003b578063f5efcd791461003b575b600080fd5b61004e61004936600461011c565b610050565b005b604080518b815263ffffffff8916602082015273ffffffffffffffffffffffffffffffffffffffff88811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b8061040081018310156100d957600080fd5b92915050565b803563ffffffff811681146100f357600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146100f357600080fd5b6000806000806000806000806000806000806109208d8f03121561013f57600080fd5b6101498e8e6100c7565b9b506101598e6104008f016100c7565b9a506108008d013599506108208d013598506108408d013597506101806108608e016100df565b965061018f6108808e016100f8565b955061019e6108a08e016100df565b94506101ad6108c08e016100f8565b93506108e08d013592506109008d013567ffffffffffffffff808211156101d357600080fd5b818f0191508f601f8301126101e757600080fd5b80823511156101f557600080fd5b508e60208235830101111561020957600080fd5b60208101925080359150509295989b509295989b509295989b56fea26469706673582212201bdd4081435a27b9ab2f7421c2d1f3979d52c6cece33269bd75823a6e6a7fe2b64736f6c63430008140033", +} + +// ClaimmockABI is the input ABI used to generate the binding from. +// Deprecated: Use ClaimmockMetaData.ABI instead. +var ClaimmockABI = ClaimmockMetaData.ABI + +// ClaimmockBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use ClaimmockMetaData.Bin instead. +var ClaimmockBin = ClaimmockMetaData.Bin + +// DeployClaimmock deploys a new Ethereum contract, binding an instance of Claimmock to it. +func DeployClaimmock(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Claimmock, error) { + parsed, err := ClaimmockMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ClaimmockBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Claimmock{ClaimmockCaller: ClaimmockCaller{contract: contract}, ClaimmockTransactor: ClaimmockTransactor{contract: contract}, ClaimmockFilterer: ClaimmockFilterer{contract: contract}}, nil +} + +// Claimmock is an auto generated Go binding around an Ethereum contract. +type Claimmock struct { + ClaimmockCaller // Read-only binding to the contract + ClaimmockTransactor // Write-only binding to the contract + ClaimmockFilterer // Log filterer for contract events +} + +// ClaimmockCaller is an auto generated read-only Go binding around an Ethereum contract. +type ClaimmockCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ClaimmockTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ClaimmockTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ClaimmockFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ClaimmockFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ClaimmockSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ClaimmockSession struct { + Contract *Claimmock // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ClaimmockCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ClaimmockCallerSession struct { + Contract *ClaimmockCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ClaimmockTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ClaimmockTransactorSession struct { + Contract *ClaimmockTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ClaimmockRaw is an auto generated low-level Go binding around an Ethereum contract. +type ClaimmockRaw struct { + Contract *Claimmock // Generic contract binding to access the raw methods on +} + +// ClaimmockCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ClaimmockCallerRaw struct { + Contract *ClaimmockCaller // Generic read-only contract binding to access the raw methods on +} + +// ClaimmockTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ClaimmockTransactorRaw struct { + Contract *ClaimmockTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewClaimmock creates a new instance of Claimmock, bound to a specific deployed contract. +func NewClaimmock(address common.Address, backend bind.ContractBackend) (*Claimmock, error) { + contract, err := bindClaimmock(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Claimmock{ClaimmockCaller: ClaimmockCaller{contract: contract}, ClaimmockTransactor: ClaimmockTransactor{contract: contract}, ClaimmockFilterer: ClaimmockFilterer{contract: contract}}, nil +} + +// NewClaimmockCaller creates a new read-only instance of Claimmock, bound to a specific deployed contract. +func NewClaimmockCaller(address common.Address, caller bind.ContractCaller) (*ClaimmockCaller, error) { + contract, err := bindClaimmock(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ClaimmockCaller{contract: contract}, nil +} + +// NewClaimmockTransactor creates a new write-only instance of Claimmock, bound to a specific deployed contract. +func NewClaimmockTransactor(address common.Address, transactor bind.ContractTransactor) (*ClaimmockTransactor, error) { + contract, err := bindClaimmock(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ClaimmockTransactor{contract: contract}, nil +} + +// NewClaimmockFilterer creates a new log filterer instance of Claimmock, bound to a specific deployed contract. +func NewClaimmockFilterer(address common.Address, filterer bind.ContractFilterer) (*ClaimmockFilterer, error) { + contract, err := bindClaimmock(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ClaimmockFilterer{contract: contract}, nil +} + +// bindClaimmock binds a generic wrapper to an already deployed contract. +func bindClaimmock(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ClaimmockMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Claimmock *ClaimmockRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Claimmock.Contract.ClaimmockCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Claimmock *ClaimmockRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Claimmock.Contract.ClaimmockTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Claimmock *ClaimmockRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Claimmock.Contract.ClaimmockTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Claimmock *ClaimmockCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Claimmock.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Claimmock *ClaimmockTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Claimmock.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Claimmock *ClaimmockTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Claimmock.Contract.contract.Transact(opts, method, params...) +} + +// ClaimAsset is a paid mutator transaction binding the contract method 0xccaa2d11. +// +// Solidity: function claimAsset(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmock *ClaimmockTransactor) ClaimAsset(opts *bind.TransactOpts, smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originTokenAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmock.contract.Transact(opts, "claimAsset", smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originTokenAddress, destinationNetwork, destinationAddress, amount, metadata) +} + +// ClaimAsset is a paid mutator transaction binding the contract method 0xccaa2d11. +// +// Solidity: function claimAsset(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmock *ClaimmockSession) ClaimAsset(smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originTokenAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmock.Contract.ClaimAsset(&_Claimmock.TransactOpts, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originTokenAddress, destinationNetwork, destinationAddress, amount, metadata) +} + +// ClaimAsset is a paid mutator transaction binding the contract method 0xccaa2d11. +// +// Solidity: function claimAsset(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmock *ClaimmockTransactorSession) ClaimAsset(smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originTokenAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmock.Contract.ClaimAsset(&_Claimmock.TransactOpts, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originTokenAddress, destinationNetwork, destinationAddress, amount, metadata) +} + +// ClaimMessage is a paid mutator transaction binding the contract method 0xf5efcd79. +// +// Solidity: function claimMessage(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmock *ClaimmockTransactor) ClaimMessage(opts *bind.TransactOpts, smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmock.contract.Transact(opts, "claimMessage", smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originAddress, destinationNetwork, destinationAddress, amount, metadata) +} + +// ClaimMessage is a paid mutator transaction binding the contract method 0xf5efcd79. +// +// Solidity: function claimMessage(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmock *ClaimmockSession) ClaimMessage(smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmock.Contract.ClaimMessage(&_Claimmock.TransactOpts, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originAddress, destinationNetwork, destinationAddress, amount, metadata) +} + +// ClaimMessage is a paid mutator transaction binding the contract method 0xf5efcd79. +// +// Solidity: function claimMessage(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmock *ClaimmockTransactorSession) ClaimMessage(smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmock.Contract.ClaimMessage(&_Claimmock.TransactOpts, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originAddress, destinationNetwork, destinationAddress, amount, metadata) +} + +// ClaimmockClaimEventIterator is returned from FilterClaimEvent and is used to iterate over the raw logs and unpacked data for ClaimEvent events raised by the Claimmock contract. +type ClaimmockClaimEventIterator struct { + Event *ClaimmockClaimEvent // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ClaimmockClaimEventIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ClaimmockClaimEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ClaimmockClaimEvent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ClaimmockClaimEventIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ClaimmockClaimEventIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ClaimmockClaimEvent represents a ClaimEvent event raised by the Claimmock contract. +type ClaimmockClaimEvent struct { + GlobalIndex *big.Int + OriginNetwork uint32 + OriginAddress common.Address + DestinationAddress common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterClaimEvent is a free log retrieval operation binding the contract event 0x1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d. +// +// Solidity: event ClaimEvent(uint256 globalIndex, uint32 originNetwork, address originAddress, address destinationAddress, uint256 amount) +func (_Claimmock *ClaimmockFilterer) FilterClaimEvent(opts *bind.FilterOpts) (*ClaimmockClaimEventIterator, error) { + + logs, sub, err := _Claimmock.contract.FilterLogs(opts, "ClaimEvent") + if err != nil { + return nil, err + } + return &ClaimmockClaimEventIterator{contract: _Claimmock.contract, event: "ClaimEvent", logs: logs, sub: sub}, nil +} + +// WatchClaimEvent is a free log subscription operation binding the contract event 0x1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d. +// +// Solidity: event ClaimEvent(uint256 globalIndex, uint32 originNetwork, address originAddress, address destinationAddress, uint256 amount) +func (_Claimmock *ClaimmockFilterer) WatchClaimEvent(opts *bind.WatchOpts, sink chan<- *ClaimmockClaimEvent) (event.Subscription, error) { + + logs, sub, err := _Claimmock.contract.WatchLogs(opts, "ClaimEvent") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ClaimmockClaimEvent) + if err := _Claimmock.contract.UnpackLog(event, "ClaimEvent", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseClaimEvent is a log parse operation binding the contract event 0x1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d. +// +// Solidity: event ClaimEvent(uint256 globalIndex, uint32 originNetwork, address originAddress, address destinationAddress, uint256 amount) +func (_Claimmock *ClaimmockFilterer) ParseClaimEvent(log types.Log) (*ClaimmockClaimEvent, error) { + event := new(ClaimmockClaimEvent) + if err := _Claimmock.contract.UnpackLog(event, "ClaimEvent", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/test/contracts/claimmockcaller/ClaimMockCaller.sol b/test/contracts/claimmockcaller/ClaimMockCaller.sol new file mode 100644 index 00000000..914eecbd --- /dev/null +++ b/test/contracts/claimmockcaller/ClaimMockCaller.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: AGPL-3.0 + +pragma solidity 0.8.20; + + +interface IClaimMock { + function claimAsset(bytes32[32] calldata smtProofLocalExitRoot,bytes32[32] calldata smtProofRollupExitRoot,uint256 globalIndex,bytes32 mainnetExitRoot,bytes32 rollupExitRoot,uint32 originNetwork,address originTokenAddress,uint32 destinationNetwork,address destinationAddress,uint256 amount,bytes calldata metadata) external; + function claimMessage(bytes32[32] calldata smtProofLocalExitRoot,bytes32[32] calldata smtProofRollupExitRoot,uint256 globalIndex,bytes32 mainnetExitRoot,bytes32 rollupExitRoot,uint32 originNetwork,address originAddress,uint32 destinationNetwork,address destinationAddress,uint256 amount,bytes calldata metadata) external; +} + +contract ClaimMockCaller { + IClaimMock public immutable claimMock; + uint8 constant _DEPOSIT_CONTRACT_TREE_DEPTH = 32; + + constructor( + IClaimMock _claimMock + ) { + claimMock = _claimMock; + } + + function claimAsset( + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, + uint256 globalIndex, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originTokenAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata + ) external { + claimMock.claimAsset( + smtProofLocalExitRoot, + smtProofRollupExitRoot, + globalIndex, + mainnetExitRoot, + rollupExitRoot, + originNetwork, + originTokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ); + } + + function claimMessage( + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofLocalExitRoot, + bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProofRollupExitRoot, + uint256 globalIndex, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata + ) external { + claimMock.claimMessage( + smtProofLocalExitRoot, + smtProofRollupExitRoot, + globalIndex, + mainnetExitRoot, + rollupExitRoot, + originNetwork, + originAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ); + } +} \ No newline at end of file diff --git a/test/contracts/claimmockcaller/claimmockcaller.go b/test/contracts/claimmockcaller/claimmockcaller.go new file mode 100644 index 00000000..d0dc38eb --- /dev/null +++ b/test/contracts/claimmockcaller/claimmockcaller.go @@ -0,0 +1,276 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package claimmockcaller + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// ClaimmockcallerMetaData contains all meta data concerning the Claimmockcaller contract. +var ClaimmockcallerMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"contractIClaimMock\",\"name\":\"_claimMock\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofLocalExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofRollupExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"uint256\",\"name\":\"globalIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"mainnetExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"rollupExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"originNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"destinationNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"name\":\"claimAsset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofLocalExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofRollupExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"uint256\",\"name\":\"globalIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"mainnetExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"rollupExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"originNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"destinationNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"name\":\"claimMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimMock\",\"outputs\":[{\"internalType\":\"contractIClaimMock\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60a060405234801561001057600080fd5b5060405161050238038061050283398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b60805161046b61009760003960008181604b0152818160fb01526101c3015261046b6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806383f5b00614610046578063ccaa2d1114610096578063f5efcd79146100ab575b600080fd5b61006d7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100a96100a4366004610263565b6100be565b005b6100a96100b9366004610263565b610186565b6040517fccaa2d1100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063ccaa2d1190610146908f908f908f908f908f908f908f908f908f908f908f908f9060040161036b565b600060405180830381600087803b15801561016057600080fd5b505af1158015610174573d6000803e3d6000fd5b50505050505050505050505050505050565b6040517ff5efcd7900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f5efcd7990610146908f908f908f908f908f908f908f908f908f908f908f908f9060040161036b565b80610400810183101561022057600080fd5b92915050565b803563ffffffff8116811461023a57600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461023a57600080fd5b6000806000806000806000806000806000806109208d8f03121561028657600080fd5b6102908e8e61020e565b9b506102a08e6104008f0161020e565b9a506108008d013599506108208d013598506108408d013597506102c76108608e01610226565b96506102d66108808e0161023f565b95506102e56108a08e01610226565b94506102f46108c08e0161023f565b93506108e08d013592506109008d013567ffffffffffffffff8082111561031a57600080fd5b818f0191508f601f83011261032e57600080fd5b808235111561033c57600080fd5b508e60208235830101111561035057600080fd5b60208101925080359150509295989b509295989b509295989b565b6000610400808f8437808e82850137508b6108008301528a6108208301528961084083015263ffffffff808a1661086084015273ffffffffffffffffffffffffffffffffffffffff808a166108808501528189166108a08501528088166108c08501525050846108e0830152610920610900830152826109208301526109408385828501376000838501820152601f9093017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169091019091019c9b50505050505050505050505056fea26469706673582212206727c3a78a95fb986d1a4568ebb299bd4398120ac4cd67a415f2c5c02e5ee78f64736f6c63430008140033", +} + +// ClaimmockcallerABI is the input ABI used to generate the binding from. +// Deprecated: Use ClaimmockcallerMetaData.ABI instead. +var ClaimmockcallerABI = ClaimmockcallerMetaData.ABI + +// ClaimmockcallerBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use ClaimmockcallerMetaData.Bin instead. +var ClaimmockcallerBin = ClaimmockcallerMetaData.Bin + +// DeployClaimmockcaller deploys a new Ethereum contract, binding an instance of Claimmockcaller to it. +func DeployClaimmockcaller(auth *bind.TransactOpts, backend bind.ContractBackend, _claimMock common.Address) (common.Address, *types.Transaction, *Claimmockcaller, error) { + parsed, err := ClaimmockcallerMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ClaimmockcallerBin), backend, _claimMock) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Claimmockcaller{ClaimmockcallerCaller: ClaimmockcallerCaller{contract: contract}, ClaimmockcallerTransactor: ClaimmockcallerTransactor{contract: contract}, ClaimmockcallerFilterer: ClaimmockcallerFilterer{contract: contract}}, nil +} + +// Claimmockcaller is an auto generated Go binding around an Ethereum contract. +type Claimmockcaller struct { + ClaimmockcallerCaller // Read-only binding to the contract + ClaimmockcallerTransactor // Write-only binding to the contract + ClaimmockcallerFilterer // Log filterer for contract events +} + +// ClaimmockcallerCaller is an auto generated read-only Go binding around an Ethereum contract. +type ClaimmockcallerCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ClaimmockcallerTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ClaimmockcallerTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ClaimmockcallerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ClaimmockcallerFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ClaimmockcallerSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ClaimmockcallerSession struct { + Contract *Claimmockcaller // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ClaimmockcallerCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ClaimmockcallerCallerSession struct { + Contract *ClaimmockcallerCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ClaimmockcallerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ClaimmockcallerTransactorSession struct { + Contract *ClaimmockcallerTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ClaimmockcallerRaw is an auto generated low-level Go binding around an Ethereum contract. +type ClaimmockcallerRaw struct { + Contract *Claimmockcaller // Generic contract binding to access the raw methods on +} + +// ClaimmockcallerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ClaimmockcallerCallerRaw struct { + Contract *ClaimmockcallerCaller // Generic read-only contract binding to access the raw methods on +} + +// ClaimmockcallerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ClaimmockcallerTransactorRaw struct { + Contract *ClaimmockcallerTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewClaimmockcaller creates a new instance of Claimmockcaller, bound to a specific deployed contract. +func NewClaimmockcaller(address common.Address, backend bind.ContractBackend) (*Claimmockcaller, error) { + contract, err := bindClaimmockcaller(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Claimmockcaller{ClaimmockcallerCaller: ClaimmockcallerCaller{contract: contract}, ClaimmockcallerTransactor: ClaimmockcallerTransactor{contract: contract}, ClaimmockcallerFilterer: ClaimmockcallerFilterer{contract: contract}}, nil +} + +// NewClaimmockcallerCaller creates a new read-only instance of Claimmockcaller, bound to a specific deployed contract. +func NewClaimmockcallerCaller(address common.Address, caller bind.ContractCaller) (*ClaimmockcallerCaller, error) { + contract, err := bindClaimmockcaller(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ClaimmockcallerCaller{contract: contract}, nil +} + +// NewClaimmockcallerTransactor creates a new write-only instance of Claimmockcaller, bound to a specific deployed contract. +func NewClaimmockcallerTransactor(address common.Address, transactor bind.ContractTransactor) (*ClaimmockcallerTransactor, error) { + contract, err := bindClaimmockcaller(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ClaimmockcallerTransactor{contract: contract}, nil +} + +// NewClaimmockcallerFilterer creates a new log filterer instance of Claimmockcaller, bound to a specific deployed contract. +func NewClaimmockcallerFilterer(address common.Address, filterer bind.ContractFilterer) (*ClaimmockcallerFilterer, error) { + contract, err := bindClaimmockcaller(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ClaimmockcallerFilterer{contract: contract}, nil +} + +// bindClaimmockcaller binds a generic wrapper to an already deployed contract. +func bindClaimmockcaller(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ClaimmockcallerMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Claimmockcaller *ClaimmockcallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Claimmockcaller.Contract.ClaimmockcallerCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Claimmockcaller *ClaimmockcallerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Claimmockcaller.Contract.ClaimmockcallerTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Claimmockcaller *ClaimmockcallerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Claimmockcaller.Contract.ClaimmockcallerTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Claimmockcaller *ClaimmockcallerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Claimmockcaller.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Claimmockcaller *ClaimmockcallerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Claimmockcaller.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Claimmockcaller *ClaimmockcallerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Claimmockcaller.Contract.contract.Transact(opts, method, params...) +} + +// ClaimMock is a free data retrieval call binding the contract method 0x83f5b006. +// +// Solidity: function claimMock() view returns(address) +func (_Claimmockcaller *ClaimmockcallerCaller) ClaimMock(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Claimmockcaller.contract.Call(opts, &out, "claimMock") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// ClaimMock is a free data retrieval call binding the contract method 0x83f5b006. +// +// Solidity: function claimMock() view returns(address) +func (_Claimmockcaller *ClaimmockcallerSession) ClaimMock() (common.Address, error) { + return _Claimmockcaller.Contract.ClaimMock(&_Claimmockcaller.CallOpts) +} + +// ClaimMock is a free data retrieval call binding the contract method 0x83f5b006. +// +// Solidity: function claimMock() view returns(address) +func (_Claimmockcaller *ClaimmockcallerCallerSession) ClaimMock() (common.Address, error) { + return _Claimmockcaller.Contract.ClaimMock(&_Claimmockcaller.CallOpts) +} + +// ClaimAsset is a paid mutator transaction binding the contract method 0xccaa2d11. +// +// Solidity: function claimAsset(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmockcaller *ClaimmockcallerTransactor) ClaimAsset(opts *bind.TransactOpts, smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originTokenAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmockcaller.contract.Transact(opts, "claimAsset", smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originTokenAddress, destinationNetwork, destinationAddress, amount, metadata) +} + +// ClaimAsset is a paid mutator transaction binding the contract method 0xccaa2d11. +// +// Solidity: function claimAsset(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmockcaller *ClaimmockcallerSession) ClaimAsset(smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originTokenAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmockcaller.Contract.ClaimAsset(&_Claimmockcaller.TransactOpts, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originTokenAddress, destinationNetwork, destinationAddress, amount, metadata) +} + +// ClaimAsset is a paid mutator transaction binding the contract method 0xccaa2d11. +// +// Solidity: function claimAsset(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmockcaller *ClaimmockcallerTransactorSession) ClaimAsset(smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originTokenAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmockcaller.Contract.ClaimAsset(&_Claimmockcaller.TransactOpts, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originTokenAddress, destinationNetwork, destinationAddress, amount, metadata) +} + +// ClaimMessage is a paid mutator transaction binding the contract method 0xf5efcd79. +// +// Solidity: function claimMessage(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmockcaller *ClaimmockcallerTransactor) ClaimMessage(opts *bind.TransactOpts, smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmockcaller.contract.Transact(opts, "claimMessage", smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originAddress, destinationNetwork, destinationAddress, amount, metadata) +} + +// ClaimMessage is a paid mutator transaction binding the contract method 0xf5efcd79. +// +// Solidity: function claimMessage(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmockcaller *ClaimmockcallerSession) ClaimMessage(smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmockcaller.Contract.ClaimMessage(&_Claimmockcaller.TransactOpts, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originAddress, destinationNetwork, destinationAddress, amount, metadata) +} + +// ClaimMessage is a paid mutator transaction binding the contract method 0xf5efcd79. +// +// Solidity: function claimMessage(bytes32[32] smtProofLocalExitRoot, bytes32[32] smtProofRollupExitRoot, uint256 globalIndex, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes metadata) returns() +func (_Claimmockcaller *ClaimmockcallerTransactorSession) ClaimMessage(smtProofLocalExitRoot [32][32]byte, smtProofRollupExitRoot [32][32]byte, globalIndex *big.Int, mainnetExitRoot [32]byte, rollupExitRoot [32]byte, originNetwork uint32, originAddress common.Address, destinationNetwork uint32, destinationAddress common.Address, amount *big.Int, metadata []byte) (*types.Transaction, error) { + return _Claimmockcaller.Contract.ClaimMessage(&_Claimmockcaller.TransactOpts, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originAddress, destinationNetwork, destinationAddress, amount, metadata) +} From 8b90e2eb0a4197e8555f2e1df88b33f5d917006d Mon Sep 17 00:00:00 2001 From: bros Date: Fri, 30 Aug 2024 09:05:38 +0000 Subject: [PATCH 04/31] decoding direct and indeirecr assets and messages works --- bridgesync/claimcalldata_test.go | 126 ++++++++++++++++++++++++------- bridgesync/downloader.go | 58 ++++++++++---- bridgesync/processor.go | 16 ++-- 3 files changed, 150 insertions(+), 50 deletions(-) diff --git a/bridgesync/claimcalldata_test.go b/bridgesync/claimcalldata_test.go index 17e7db5a..20c1b7c5 100644 --- a/bridgesync/claimcalldata_test.go +++ b/bridgesync/claimcalldata_test.go @@ -11,17 +11,26 @@ import ( "github.com/0xPolygon/cdk/test/contracts/claimmockcaller" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/stretchr/testify/require" ) +type testCase struct { + description string + bridgeAddr common.Address + log types.Log + expectedClaim Claim +} + func TestClaimCalldata(t *testing.T) { + testCases := []testCase{} // Setup Docker L1 ctx := context.Background() msg, err := exec.Command("bash", "-l", "-c", "docker compose up -d").CombinedOutput() require.NoError(t, err, string(msg)) - time.Sleep(time.Second * 5) + time.Sleep(time.Second * 1) defer func() { msg, err = exec.Command("bash", "-l", "-c", "docker compose down").CombinedOutput() require.NoError(t, err, string(msg)) @@ -57,10 +66,12 @@ func TestClaimCalldata(t *testing.T) { RollupExitRoot: common.HexToHash("dead"), ProofLocalExitRoot: proofLocalH, ProofRollupExitRoot: proofRollupH, + DestinationNetwork: 0, + Metadata: []byte{}, } - auth.GasLimit = 999999 + auth.GasLimit = 999999 // for some reason gas estimation fails :( - // direct call + // direct call claim asset tx, err := bridgeContract.ClaimAsset( auth, proofLocal, @@ -76,23 +87,17 @@ func TestClaimCalldata(t *testing.T) { nil, ) require.NoError(t, err) - time.Sleep(2 * time.Second) + time.Sleep(1 * time.Second) r, err := client.TransactionReceipt(ctx, tx.Hash()) - require.NoError(t, err) - claimEvent, err := bridgeContract.ParseClaimEvent(*r.Logs[0]) - require.NoError(t, err) - actualClaim := Claim{ - GlobalIndex: claimEvent.GlobalIndex, - OriginNetwork: claimEvent.OriginNetwork, - OriginAddress: claimEvent.OriginAddress, - DestinationAddress: claimEvent.DestinationAddress, - Amount: claimEvent.Amount, - } - err = setClaimCalldata(client, bridgeAddr, tx.Hash(), &actualClaim) - require.NoError(t, err) - require.Equal(t, expectedClaim, actualClaim) + expectedClaim.IsMessage = false + testCases = append(testCases, testCase{ + description: "direct call to claim asset", + bridgeAddr: bridgeAddr, + log: *r.Logs[0], + expectedClaim: expectedClaim, + }) - // indirect call + // indirect call claim asset tx, err = claimCaller.ClaimAsset( auth, proofLocal, @@ -108,19 +113,82 @@ func TestClaimCalldata(t *testing.T) { nil, ) require.NoError(t, err) - time.Sleep(2 * time.Second) + time.Sleep(1 * time.Second) r, err = client.TransactionReceipt(ctx, tx.Hash()) + expectedClaim.IsMessage = false + testCases = append(testCases, testCase{ + description: "indirect call to claim asset", + bridgeAddr: bridgeAddr, + log: *r.Logs[0], + expectedClaim: expectedClaim, + }) + + // direct call claim message + tx, err = bridgeContract.ClaimMessage( + auth, + proofLocal, + proofRollup, + expectedClaim.GlobalIndex, + expectedClaim.MainnetExitRoot, + expectedClaim.RollupExitRoot, + expectedClaim.OriginNetwork, + expectedClaim.OriginAddress, + 0, + expectedClaim.DestinationAddress, + expectedClaim.Amount, + nil, + ) require.NoError(t, err) - claimEvent, err = bridgeContract.ParseClaimEvent(*r.Logs[0]) + time.Sleep(1 * time.Second) + r, err = client.TransactionReceipt(ctx, tx.Hash()) + expectedClaim.IsMessage = true + testCases = append(testCases, testCase{ + description: "direct call to claim message", + bridgeAddr: bridgeAddr, + log: *r.Logs[0], + expectedClaim: expectedClaim, + }) + + // indirect call claim message + tx, err = claimCaller.ClaimMessage( + auth, + proofLocal, + proofRollup, + expectedClaim.GlobalIndex, + expectedClaim.MainnetExitRoot, + expectedClaim.RollupExitRoot, + expectedClaim.OriginNetwork, + expectedClaim.OriginAddress, + 0, + expectedClaim.DestinationAddress, + expectedClaim.Amount, + nil, + ) require.NoError(t, err) - actualClaim = Claim{ - GlobalIndex: claimEvent.GlobalIndex, - OriginNetwork: claimEvent.OriginNetwork, - OriginAddress: claimEvent.OriginAddress, - DestinationAddress: claimEvent.DestinationAddress, - Amount: claimEvent.Amount, + time.Sleep(1 * time.Second) + r, err = client.TransactionReceipt(ctx, tx.Hash()) + expectedClaim.IsMessage = true + testCases = append(testCases, testCase{ + description: "indirect call to claim message", + bridgeAddr: bridgeAddr, + log: *r.Logs[0], + expectedClaim: expectedClaim, + }) + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + claimEvent, err := bridgeContract.ParseClaimEvent(tc.log) + require.NoError(t, err) + actualClaim := Claim{ + GlobalIndex: claimEvent.GlobalIndex, + OriginNetwork: claimEvent.OriginNetwork, + OriginAddress: claimEvent.OriginAddress, + DestinationAddress: claimEvent.DestinationAddress, + Amount: claimEvent.Amount, + } + err = setClaimCalldata(client, tc.bridgeAddr, tc.log.TxHash, &actualClaim) + require.NoError(t, err) + require.Equal(t, tc.expectedClaim, actualClaim) + }) } - err = setClaimCalldata(client, bridgeAddr, tx.Hash(), &actualClaim) - require.NoError(t, err) - require.Equal(t, expectedClaim, actualClaim) } diff --git a/bridgesync/downloader.go b/bridgesync/downloader.go index 59ea1157..155252dc 100644 --- a/bridgesync/downloader.go +++ b/bridgesync/downloader.go @@ -26,6 +26,7 @@ var ( claimEventSignature = crypto.Keccak256Hash([]byte("ClaimEvent(uint256,uint32,address,address,uint256)")) claimEventSignaturePreEtrog = crypto.Keccak256Hash([]byte("ClaimEvent(uint32,uint32,address,address,uint256)")) methodIDClaimAsset = common.Hex2Bytes("ccaa2d11") + methodIDClaimMessage = common.Hex2Bytes("f5efcd79") ) type EthClienter interface { @@ -160,19 +161,38 @@ func setClaimIfFoundOnInput(input []byte, claim *Claim) (bool, error) { return false, err } methodId := input[:4] - - // Ignore other methods - if !bytes.Equal(methodId, methodIDClaimAsset) { - return false, nil - } - // Recover Method from signature and ABI method, err := smcAbi.MethodById(methodId) if err != nil { return false, err } + data, err := method.Inputs.Unpack(input[4:]) + if err != nil { + return false, err + } + // Ignore other methods + if bytes.Equal(methodId, methodIDClaimAsset) || bytes.Equal(methodId, methodIDClaimMessage) { + found, err := decodeClaimCallDataAndSetIfFound(data, claim) + if err != nil { + return false, err + } + if found { + if bytes.Equal(methodId, methodIDClaimMessage) { + claim.IsMessage = true + } + return true, nil + } + return false, nil + } else { + return false, nil + } + // TODO: support both claim asset & message, check if previous versions need special treatment + // TODO: ignore claim messages that don't have value +} - /* Unpack method inputs +func decodeClaimCallDataAndSetIfFound(data []interface{}, claim *Claim) (bool, error) { + /* Unpack method inputs. Note that both claimAsset and claimMessage have the same interface + for the relevant parts claimAsset( 0: smtProofLocalExitRoot, 1: smtProofRollupExitRoot, @@ -186,14 +206,20 @@ func setClaimIfFoundOnInput(input []byte, claim *Claim) (bool, error) { 9: amount, 10: metadata, ) + claimMessage( + 0: smtProofLocalExitRoot, + 1: smtProofRollupExitRoot, + 2: globalIndex, + 3: mainnetExitRoot, + 4: rollupExitRoot, + 5: originNetwork, + 6: originAddress, + 7: destinationNetwork, + 8: destinationAddress, + 9: amount, + 10: metadata, + ) */ - data, err := method.Inputs.Unpack(input[4:]) - if err != nil { - return false, err - } - - // TODO: support both claim asset & message, check if previous versions need special treatment - // TODO: ignore claim messages that don't have value actualGlobalIndex := data[2].(*big.Int) if actualGlobalIndex.Cmp(claim.GlobalIndex) != 0 { // not the claim we're looking for @@ -207,12 +233,12 @@ func setClaimIfFoundOnInput(input []byte, claim *Claim) (bool, error) { proofLER[i] = proofLERBytes[i] proofRER[i] = proofRERBytes[i] } - // TODO: add ALL the data, hard to know what we're gonna need in the future claim.ProofLocalExitRoot = proofLER claim.ProofRollupExitRoot = proofRER claim.MainnetExitRoot = data[3].([32]byte) claim.RollupExitRoot = data[4].([32]byte) - claim.Amount = data[9].(*big.Int) + claim.DestinationNetwork = data[7].(uint32) + claim.Metadata = data[10].([]byte) return true, nil } } diff --git a/bridgesync/processor.go b/bridgesync/processor.go index 5b319e73..bd96732f 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -69,15 +69,21 @@ func (b *Bridge) Hash() common.Hash { // Claim representation of a claim event type Claim struct { - GlobalIndex *big.Int - OriginNetwork uint32 - OriginAddress common.Address - DestinationAddress common.Address - Amount *big.Int + // From claim event + GlobalIndex *big.Int + OriginNetwork uint32 + OriginAddress common.Address + DestinationAddress common.Address + Amount *big.Int + // From call data ProofLocalExitRoot [tree.DefaultHeight]common.Hash ProofRollupExitRoot [tree.DefaultHeight]common.Hash MainnetExitRoot common.Hash RollupExitRoot common.Hash + DestinationNetwork uint32 + Metadata []byte + // Meta + IsMessage bool } // Event combination of bridge and claim events From de8d8a779303610ef20546a452f6f387b76f6472 Mon Sep 17 00:00:00 2001 From: bros Date: Fri, 30 Aug 2024 09:45:12 +0000 Subject: [PATCH 05/31] connect everything --- bridgesync/bridgesync.go | 5 ++- bridgesync/downloader.go | 60 ++++++++++++++++++------------ bridgesync/e2e_test.go | 4 +- claimsponsor/e2e_test.go | 3 +- go.mod | 4 +- l1bridge2infoindexsync/e2e_test.go | 4 +- test/helpers/simulated.go | 16 ++++++++ 7 files changed, 66 insertions(+), 30 deletions(-) create mode 100644 test/helpers/simulated.go diff --git a/bridgesync/bridgesync.go b/bridgesync/bridgesync.go index e417abc3..220c33fd 100644 --- a/bridgesync/bridgesync.go +++ b/bridgesync/bridgesync.go @@ -47,6 +47,7 @@ func NewL1( waitForNewBlocksPeriod, retryAfterErrorPeriod, maxRetryAttemptsAfterError, + false, ) } @@ -77,6 +78,7 @@ func NewL2( waitForNewBlocksPeriod, retryAfterErrorPeriod, maxRetryAttemptsAfterError, + true, ) } @@ -93,6 +95,7 @@ func newBridgeSync( waitForNewBlocksPeriod time.Duration, retryAfterErrorPeriod time.Duration, maxRetryAttemptsAfterError int, + syncFullClaims bool, ) (*BridgeSync, error) { processor, err := newProcessor(ctx, dbPath, l1OrL2ID) if err != nil { @@ -115,7 +118,7 @@ func newBridgeSync( RetryAfterErrorPeriod: retryAfterErrorPeriod, } - appender, err := buildAppender(ethClient, bridge) + appender, err := buildAppender(ethClient, bridge, syncFullClaims) if err != nil { return nil, err } diff --git a/bridgesync/downloader.go b/bridgesync/downloader.go index 155252dc..6366df2c 100644 --- a/bridgesync/downloader.go +++ b/bridgesync/downloader.go @@ -17,7 +17,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" "github.com/golang-collections/collections/stack" ) @@ -34,9 +34,14 @@ type EthClienter interface { ethereum.BlockNumberReader ethereum.ChainReader bind.ContractBackend + Client() *rpc.Client } -func buildAppender(client EthClienter, bridge common.Address) (sync.LogAppenderMap, error) { +type ClientCaller interface { + Call(result interface{}, method string, args ...interface{}) error +} + +func buildAppender(client EthClienter, bridge common.Address, syncFullClaims bool) (sync.LogAppenderMap, error) { bridgeContractV1, err := polygonzkevmbridge.NewPolygonzkevmbridge(bridge, client) if err != nil { return nil, err @@ -69,38 +74,46 @@ func buildAppender(client EthClienter, bridge common.Address) (sync.LogAppenderM } appender[claimEventSignature] = func(b *sync.EVMBlock, l types.Log) error { - claim, err := bridgeContractV2.ParseClaimEvent(l) + claimEvent, err := bridgeContractV2.ParseClaimEvent(l) if err != nil { return fmt.Errorf( "error parsing log %+v using d.bridgeContractV2.ParseClaimEvent: %v", l, err, ) } - b.Events = append(b.Events, Event{Claim: &Claim{ - GlobalIndex: claim.GlobalIndex, - OriginNetwork: claim.OriginNetwork, - OriginAddress: claim.OriginAddress, - DestinationAddress: claim.DestinationAddress, - Amount: claim.Amount, - }}) + claim := &Claim{ + GlobalIndex: claimEvent.GlobalIndex, + OriginNetwork: claimEvent.OriginNetwork, + OriginAddress: claimEvent.OriginAddress, + DestinationAddress: claimEvent.DestinationAddress, + Amount: claimEvent.Amount, + } + if syncFullClaims { + setClaimCalldata(client, bridge, l.TxHash, claim) + } + b.Events = append(b.Events, Event{Claim: claim}) return nil } appender[claimEventSignaturePreEtrog] = func(b *sync.EVMBlock, l types.Log) error { - claim, err := bridgeContractV1.ParseClaimEvent(l) + claimEvent, err := bridgeContractV1.ParseClaimEvent(l) if err != nil { return fmt.Errorf( "error parsing log %+v using d.bridgeContractV1.ParseClaimEvent: %v", l, err, ) } - b.Events = append(b.Events, Event{Claim: &Claim{ - GlobalIndex: big.NewInt(int64(claim.Index)), - OriginNetwork: claim.OriginNetwork, - OriginAddress: claim.OriginAddress, - DestinationAddress: claim.DestinationAddress, - Amount: claim.Amount, - }}) + claim := &Claim{ + GlobalIndex: big.NewInt(int64(claimEvent.Index)), + OriginNetwork: claimEvent.OriginNetwork, + OriginAddress: claimEvent.OriginAddress, + DestinationAddress: claimEvent.DestinationAddress, + Amount: claimEvent.Amount, + } + if syncFullClaims { + setClaimCalldata(client, bridge, l.TxHash, claim) + } + b.Events = append(b.Events, Event{Claim: claim}) return nil } @@ -108,9 +121,9 @@ func buildAppender(client EthClienter, bridge common.Address) (sync.LogAppenderM } type call struct { - To common.Address `json:"to"` - Value *rpcTypes.ArgBig `json:"value"` - // Err *string `json:"error"` + To common.Address `json:"to"` + Value *rpcTypes.ArgBig `json:"value"` + Err *string `json:"error"` Input rpcTypes.ArgBytes `json:"input"` Calls []call `json:"calls"` } @@ -119,7 +132,7 @@ type tracerCfg struct { Tracer string `json:"tracer"` } -func setClaimCalldata(client *ethclient.Client, bridgeAddr common.Address, txHash common.Hash, claim *Claim) error { +func setClaimCalldata(client EthClienter, bridge common.Address, txHash common.Hash, claim *Claim) error { c := &call{} err := client.Client().Call(c, "debug_traceTransaction", txHash, tracerCfg{Tracer: "callTracer"}) if err != nil { @@ -136,7 +149,7 @@ func setClaimCalldata(client *ethclient.Client, bridgeAddr common.Address, txHas break } currentCall := callStack.Pop().(call) - if currentCall.To == bridgeAddr { + if currentCall.To == bridge { found, err := setClaimIfFoundOnInput( currentCall.Input, claim, @@ -187,7 +200,6 @@ func setClaimIfFoundOnInput(input []byte, claim *Claim) (bool, error) { return false, nil } // TODO: support both claim asset & message, check if previous versions need special treatment - // TODO: ignore claim messages that don't have value } func decodeClaimCallDataAndSetIfFound(data []interface{}, claim *Claim) (bool, error) { diff --git a/bridgesync/e2e_test.go b/bridgesync/e2e_test.go index db8be873..6eff5548 100644 --- a/bridgesync/e2e_test.go +++ b/bridgesync/e2e_test.go @@ -11,6 +11,7 @@ import ( "github.com/0xPolygon/cdk/bridgesync" "github.com/0xPolygon/cdk/etherman" "github.com/0xPolygon/cdk/reorgdetector" + "github.com/0xPolygon/cdk/test/helpers" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -55,7 +56,8 @@ func TestBridgeEventE2E(t *testing.T) { require.NoError(t, err) go rd.Start(ctx) - syncer, err := bridgesync.NewL1(ctx, dbPathSyncer, bridgeAddr, 10, etherman.LatestBlock, rd, client.Client(), 0, time.Millisecond*10, 0, 0) + testClient := helpers.TestClient{ClientRenamed: client.Client()} + syncer, err := bridgesync.NewL1(ctx, dbPathSyncer, bridgeAddr, 10, etherman.LatestBlock, rd, testClient, 0, time.Millisecond*10, 0, 0) require.NoError(t, err) go syncer.Start(ctx) diff --git a/claimsponsor/e2e_test.go b/claimsponsor/e2e_test.go index 533de113..796a09ba 100644 --- a/claimsponsor/e2e_test.go +++ b/claimsponsor/e2e_test.go @@ -22,7 +22,8 @@ func TestE2EL1toEVML2(t *testing.T) { ctx := context.Background() env := helpers.SetupAggoracleWithEVMChain(t) dbPathBridgeSyncL1 := t.TempDir() - bridgeSyncL1, err := bridgesync.NewL1(ctx, dbPathBridgeSyncL1, env.BridgeL1Addr, 10, etherman.LatestBlock, env.ReorgDetector, env.L1Client.Client(), 0, time.Millisecond*10, 0, 0) + testClient := helpers.TestClient{ClientRenamed: env.L1Client.Client()} + bridgeSyncL1, err := bridgesync.NewL1(ctx, dbPathBridgeSyncL1, env.BridgeL1Addr, 10, etherman.LatestBlock, env.ReorgDetector, testClient, 0, time.Millisecond*10, 0, 0) require.NoError(t, err) go bridgeSyncL1.Start(ctx) diff --git a/go.mod b/go.mod index 940ce107..dc65c9f9 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/0xPolygonHermez/zkevm-ethtx-manager v0.1.10-0.20240716105056-c051c96d0234 github.com/0xPolygonHermez/zkevm-synchronizer-l1 v0.7.0 github.com/ethereum/go-ethereum v1.14.5 + github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 github.com/hermeznetwork/tracerr v0.3.2 github.com/iden3/go-iden3-crypto v0.0.16 github.com/invopop/jsonschema v0.12.0 @@ -26,6 +27,7 @@ require ( go.uber.org/zap v1.27.0 golang.org/x/crypto v0.24.0 golang.org/x/net v0.26.0 + golang.org/x/sync v0.7.0 google.golang.org/grpc v1.64.0 google.golang.org/protobuf v1.34.2 ) @@ -72,7 +74,6 @@ require ( github.com/go-stack/stack v1.8.1 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/uuid v1.6.0 // indirect @@ -141,7 +142,6 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect - golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect diff --git a/l1bridge2infoindexsync/e2e_test.go b/l1bridge2infoindexsync/e2e_test.go index c2a5e982..2aa8e38f 100644 --- a/l1bridge2infoindexsync/e2e_test.go +++ b/l1bridge2infoindexsync/e2e_test.go @@ -18,6 +18,7 @@ import ( "github.com/0xPolygon/cdk/l1infotreesync" "github.com/0xPolygon/cdk/reorgdetector" "github.com/0xPolygon/cdk/test/contracts/transparentupgradableproxy" + "github.com/0xPolygon/cdk/test/helpers" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -137,7 +138,8 @@ func TestE2E(t *testing.T) { require.NoError(t, err) require.NoError(t, rd.Start(ctx)) - bridgeSync, err := bridgesync.NewL1(ctx, dbPathBridgeSync, bridgeAddr, 10, etherman.LatestBlock, rd, client.Client(), 0, time.Millisecond*10, 0, 0) + testClient := helpers.TestClient{ClientRenamed: client.Client()} + bridgeSync, err := bridgesync.NewL1(ctx, dbPathBridgeSync, bridgeAddr, 10, etherman.LatestBlock, rd, testClient, 0, time.Millisecond*10, 0, 0) require.NoError(t, err) go bridgeSync.Start(ctx) diff --git a/test/helpers/simulated.go b/test/helpers/simulated.go new file mode 100644 index 00000000..eb4cab20 --- /dev/null +++ b/test/helpers/simulated.go @@ -0,0 +1,16 @@ +package helpers + +import ( + "github.com/ethereum/go-ethereum/ethclient/simulated" + "github.com/ethereum/go-ethereum/rpc" +) + +type ClientRenamed simulated.Client + +type TestClient struct { + ClientRenamed +} + +func (tc TestClient) Client() *rpc.Client { + return nil +} From b4ad84e533c8d77a25e426531d3017a92a3d4707 Mon Sep 17 00:00:00 2001 From: bros Date: Fri, 30 Aug 2024 12:00:28 +0000 Subject: [PATCH 06/31] fix building contract scripts --- test/contracts/ClaimMock.abi | 1 - test/contracts/ClaimMock.bin | 1 - test/contracts/abi/claimmockcaller.abi | 153 +----------------- test/contracts/bin/claimmockcaller.bin | 2 +- test/contracts/bin/verifybatchesmock.bin | 2 +- .../claimmockcaller/ClaimMockCaller.sol | 2 +- .../claimmockcaller/claimmockcaller.go | 2 +- test/contracts/compile.sh | 18 ++- .../verifybatchesmock/verifybatchesmock.go | 2 +- 9 files changed, 23 insertions(+), 160 deletions(-) delete mode 100644 test/contracts/ClaimMock.abi delete mode 100644 test/contracts/ClaimMock.bin mode change 100644 => 100755 test/contracts/compile.sh diff --git a/test/contracts/ClaimMock.abi b/test/contracts/ClaimMock.abi deleted file mode 100644 index d439c7f6..00000000 --- a/test/contracts/ClaimMock.abi +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"globalIndex","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"originNetwork","type":"uint32"},{"indexed":false,"internalType":"address","name":"originAddress","type":"address"},{"indexed":false,"internalType":"address","name":"destinationAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimEvent","type":"event"},{"inputs":[{"internalType":"uint256","name":"globalIndex","type":"uint256"},{"internalType":"uint32","name":"originNetwork","type":"uint32"},{"internalType":"address","name":"originTokenAddress","type":"address"},{"internalType":"address","name":"destinationAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claimAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"globalIndex","type":"uint256"},{"internalType":"uint32","name":"originNetwork","type":"uint32"},{"internalType":"address","name":"originAddress","type":"address"},{"internalType":"address","name":"destinationAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claimMessage","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/test/contracts/ClaimMock.bin b/test/contracts/ClaimMock.bin deleted file mode 100644 index 522d1126..00000000 --- a/test/contracts/ClaimMock.bin +++ /dev/null @@ -1 +0,0 @@ -608060405234801561001057600080fd5b50610305806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636f027e4c1461003b57806392b5670b14610057575b600080fd5b610055600480360381019061005091906101d4565b610073565b005b610071600480360381019061006c91906101d4565b6100b9565b005b7f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d85858585856040516100aa95949392919061027c565b60405180910390a15050505050565b7f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d85858585856040516100f095949392919061027c565b60405180910390a15050505050565b600080fd5b6000819050919050565b61011781610104565b811461012257600080fd5b50565b6000813590506101348161010e565b92915050565b600063ffffffff82169050919050565b6101538161013a565b811461015e57600080fd5b50565b6000813590506101708161014a565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101a182610176565b9050919050565b6101b181610196565b81146101bc57600080fd5b50565b6000813590506101ce816101a8565b92915050565b600080600080600060a086880312156101f0576101ef6100ff565b5b60006101fe88828901610125565b955050602061020f88828901610161565b9450506040610220888289016101bf565b9350506060610231888289016101bf565b925050608061024288828901610125565b9150509295509295909350565b61025881610104565b82525050565b6102678161013a565b82525050565b61027681610196565b82525050565b600060a082019050610291600083018861024f565b61029e602083018761025e565b6102ab604083018661026d565b6102b8606083018561026d565b6102c5608083018461024f565b969550505050505056fea26469706673582212202e7016e57820c7c09f82ea7928de88dbf547057550cdf9e081466bdeb58198b664736f6c63430008120033 \ No newline at end of file diff --git a/test/contracts/abi/claimmockcaller.abi b/test/contracts/abi/claimmockcaller.abi index 35244b7d..b2c6e2b9 100644 --- a/test/contracts/abi/claimmockcaller.abi +++ b/test/contracts/abi/claimmockcaller.abi @@ -1,152 +1 @@ -[ - { - "inputs": [ - { - "internalType": "contract IClaimMock", - "name": "_claimMock", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "bytes32[32]", - "name": "smtProofLocalExitRoot", - "type": "bytes32[32]" - }, - { - "internalType": "bytes32[32]", - "name": "smtProofRollupExitRoot", - "type": "bytes32[32]" - }, - { - "internalType": "uint256", - "name": "globalIndex", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "mainnetExitRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "rollupExitRoot", - "type": "bytes32" - }, - { - "internalType": "uint32", - "name": "originNetwork", - "type": "uint32" - }, - { - "internalType": "address", - "name": "originTokenAddress", - "type": "address" - }, - { - "internalType": "uint32", - "name": "destinationNetwork", - "type": "uint32" - }, - { - "internalType": "address", - "name": "destinationAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "metadata", - "type": "bytes" - } - ], - "name": "claimAsset", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32[32]", - "name": "smtProofLocalExitRoot", - "type": "bytes32[32]" - }, - { - "internalType": "bytes32[32]", - "name": "smtProofRollupExitRoot", - "type": "bytes32[32]" - }, - { - "internalType": "uint256", - "name": "globalIndex", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "mainnetExitRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "rollupExitRoot", - "type": "bytes32" - }, - { - "internalType": "uint32", - "name": "originNetwork", - "type": "uint32" - }, - { - "internalType": "address", - "name": "originAddress", - "type": "address" - }, - { - "internalType": "uint32", - "name": "destinationNetwork", - "type": "uint32" - }, - { - "internalType": "address", - "name": "destinationAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "metadata", - "type": "bytes" - } - ], - "name": "claimMessage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "claimMock", - "outputs": [ - { - "internalType": "contract IClaimMock", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } - ] \ No newline at end of file +[{"inputs":[{"internalType":"contract IClaimMock","name":"_claimMock","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes32[32]","name":"smtProofLocalExitRoot","type":"bytes32[32]"},{"internalType":"bytes32[32]","name":"smtProofRollupExitRoot","type":"bytes32[32]"},{"internalType":"uint256","name":"globalIndex","type":"uint256"},{"internalType":"bytes32","name":"mainnetExitRoot","type":"bytes32"},{"internalType":"bytes32","name":"rollupExitRoot","type":"bytes32"},{"internalType":"uint32","name":"originNetwork","type":"uint32"},{"internalType":"address","name":"originTokenAddress","type":"address"},{"internalType":"uint32","name":"destinationNetwork","type":"uint32"},{"internalType":"address","name":"destinationAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"claimAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[32]","name":"smtProofLocalExitRoot","type":"bytes32[32]"},{"internalType":"bytes32[32]","name":"smtProofRollupExitRoot","type":"bytes32[32]"},{"internalType":"uint256","name":"globalIndex","type":"uint256"},{"internalType":"bytes32","name":"mainnetExitRoot","type":"bytes32"},{"internalType":"bytes32","name":"rollupExitRoot","type":"bytes32"},{"internalType":"uint32","name":"originNetwork","type":"uint32"},{"internalType":"address","name":"originAddress","type":"address"},{"internalType":"uint32","name":"destinationNetwork","type":"uint32"},{"internalType":"address","name":"destinationAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"claimMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimMock","outputs":[{"internalType":"contract IClaimMock","name":"","type":"address"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/test/contracts/bin/claimmockcaller.bin b/test/contracts/bin/claimmockcaller.bin index 3dad9a9d..6a84c36f 100644 --- a/test/contracts/bin/claimmockcaller.bin +++ b/test/contracts/bin/claimmockcaller.bin @@ -1 +1 @@ -60a060405234801561001057600080fd5b5060405161050238038061050283398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b60805161046b61009760003960008181604b0152818160fb01526101c3015261046b6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806383f5b00614610046578063ccaa2d1114610096578063f5efcd79146100ab575b600080fd5b61006d7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100a96100a4366004610263565b6100be565b005b6100a96100b9366004610263565b610186565b6040517fccaa2d1100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063ccaa2d1190610146908f908f908f908f908f908f908f908f908f908f908f908f9060040161036b565b600060405180830381600087803b15801561016057600080fd5b505af1158015610174573d6000803e3d6000fd5b50505050505050505050505050505050565b6040517ff5efcd7900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f5efcd7990610146908f908f908f908f908f908f908f908f908f908f908f908f9060040161036b565b80610400810183101561022057600080fd5b92915050565b803563ffffffff8116811461023a57600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461023a57600080fd5b6000806000806000806000806000806000806109208d8f03121561028657600080fd5b6102908e8e61020e565b9b506102a08e6104008f0161020e565b9a506108008d013599506108208d013598506108408d013597506102c76108608e01610226565b96506102d66108808e0161023f565b95506102e56108a08e01610226565b94506102f46108c08e0161023f565b93506108e08d013592506109008d013567ffffffffffffffff8082111561031a57600080fd5b818f0191508f601f83011261032e57600080fd5b808235111561033c57600080fd5b508e60208235830101111561035057600080fd5b60208101925080359150509295989b509295989b509295989b565b6000610400808f8437808e82850137508b6108008301528a6108208301528961084083015263ffffffff808a1661086084015273ffffffffffffffffffffffffffffffffffffffff808a166108808501528189166108a08501528088166108c08501525050846108e0830152610920610900830152826109208301526109408385828501376000838501820152601f9093017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169091019091019c9b50505050505050505050505056fea26469706673582212206727c3a78a95fb986d1a4568ebb299bd4398120ac4cd67a415f2c5c02e5ee78f64736f6c63430008140033 \ No newline at end of file +60a060405234801561001057600080fd5b5060405161047238038061047283398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b6080516103db61009760003960008181604b0152818160c8015261016a01526103db6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806383f5b00614610046578063ccaa2d1114610089578063f5efcd791461009e575b600080fd5b61006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61009c6100973660046101fd565b6100b1565b005b61009c6100ac3660046101fd565b610153565b60405163ccaa2d1160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ccaa2d1190610113908f908f908f908f908f908f908f908f908f908f908f908f90600401610305565b600060405180830381600087803b15801561012d57600080fd5b505af1158015610141573d6000803e3d6000fd5b50505050505050505050505050505050565b60405163f5efcd7960e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f5efcd7990610113908f908f908f908f908f908f908f908f908f908f908f908f90600401610305565b8061040081018310156101c757600080fd5b92915050565b803563ffffffff811681146101e157600080fd5b919050565b80356001600160a01b03811681146101e157600080fd5b6000806000806000806000806000806000806109208d8f03121561022057600080fd5b61022a8e8e6101b5565b9b5061023a8e6104008f016101b5565b9a506108008d013599506108208d013598506108408d013597506102616108608e016101cd565b96506102706108808e016101e6565b955061027f6108a08e016101cd565b945061028e6108c08e016101e6565b93506108e08d013592506109008d013567ffffffffffffffff808211156102b457600080fd5b818f0191508f601f8301126102c857600080fd5b80823511156102d657600080fd5b508e6020823583010111156102ea57600080fd5b60208101925080359150509295989b509295989b509295989b565b6000610400808f8437808e828501375061080082018c905261082082018b905261084082018a905263ffffffff8981166108608401526001600160a01b038981166108808501529088166108a084015286166108c08301526108e08201859052610920610900830181905282018390526109408385828501376000838501820152601f909301601f19169091019091019c9b50505050505050505050505056fea26469706673582212202321216f86560e0f29df639adc8713b3ce119002b4def8923caee0576ed8380564736f6c63430008120033 \ No newline at end of file diff --git a/test/contracts/bin/verifybatchesmock.bin b/test/contracts/bin/verifybatchesmock.bin index 83350d34..17badba8 100644 --- a/test/contracts/bin/verifybatchesmock.bin +++ b/test/contracts/bin/verifybatchesmock.bin @@ -1 +1 @@ -60a060405234801561001057600080fd5b50604051610d2e380380610d2e833981810160405281019061003291906100e1565b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250505061010e565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061009c82610071565b9050919050565b60006100ae82610091565b9050919050565b6100be816100a3565b81146100c957600080fd5b50565b6000815190506100db816100b5565b92915050565b6000602082840312156100f7576100f661006c565b5b6000610105848285016100cc565b91505092915050565b608051610bfe610130600039600081816104d501526105680152610bfe6000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80630680cf5c1461005c578063a2967d991461008c578063d02103ca146100aa578063db3abdb9146100c8578063f4e92675146100e4575b600080fd5b610076600480360381019061007191906106ae565b610102565b60405161008391906106f4565b60405180910390f35b61009461011a565b6040516100a191906106f4565b60405180910390f35b6100b26104d3565b6040516100bf919061078e565b60405180910390f35b6100e260048036038101906100dd919061084d565b6104f7565b005b6100ec610659565b6040516100f991906108d7565b60405180910390f35b60016020528060005260406000206000915090505481565b60008060008054906101000a900463ffffffff1663ffffffff1690506000810361014a576000801b9150506104d0565b60008167ffffffffffffffff811115610166576101656108f2565b5b6040519080825280602002602001820160405280156101945781602001602082028036833780820191505090505b50905060005b8281101561020057600160006001836101b3919061095a565b63ffffffff1663ffffffff168152602001908152602001600020548282815181106101e1576101e061098e565b5b60200260200101818152505080806101f8906109bd565b91505061019a565b5060008060001b90506000602090505b600184146104325760006002856102279190610a34565b6002866102349190610a65565b61023e919061095a565b905060008167ffffffffffffffff81111561025c5761025b6108f2565b5b60405190808252806020026020018201604052801561028a5781602001602082028036833780820191505090505b50905060005b828110156103eb576001836102a59190610a96565b811480156102bf575060016002886102bd9190610a34565b145b1561033757856002826102d29190610aca565b815181106102e3576102e261098e565b5b6020026020010151856040516020016102fd929190610b2d565b604051602081830303815290604052805190602001208282815181106103265761032561098e565b5b6020026020010181815250506103d8565b856002826103459190610aca565b815181106103565761035561098e565b5b602002602001015186600160028461036e9190610aca565b610378919061095a565b815181106103895761038861098e565b5b60200260200101516040516020016103a2929190610b2d565b604051602081830303815290604052805190602001208282815181106103cb576103ca61098e565b5b6020026020010181815250505b80806103e3906109bd565b915050610290565b508094508195508384604051602001610405929190610b2d565b604051602081830303815290604052805190602001209350828061042890610b59565b9350505050610210565b6000836000815181106104485761044761098e565b5b6020026020010151905060005b828110156104c6578184604051602001610470929190610b2d565b604051602081830303815290604052805190602001209150838460405160200161049b929190610b2d565b60405160208183030381529060405280519060200120935080806104be906109bd565b915050610455565b5080955050505050505b90565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008054906101000a900463ffffffff1663ffffffff168563ffffffff16111561053c57846000806101000a81548163ffffffff021916908363ffffffff1602179055505b82600160008763ffffffff1663ffffffff1681526020019081526020016000208190555080156105f9577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166333d6247d6105aa61011a565b6040518263ffffffff1660e01b81526004016105c691906106f4565b600060405180830381600087803b1580156105e057600080fd5b505af11580156105f4573d6000803e3d6000fd5b505050505b3373ffffffffffffffffffffffffffffffffffffffff168563ffffffff167faac1e7a157b259544ebacd6e8a82ae5d6c8f174e12aa48696277bcc9a661f0b486858760405161064a93929190610b91565b60405180910390a35050505050565b60008054906101000a900463ffffffff1681565b600080fd5b600063ffffffff82169050919050565b61068b81610672565b811461069657600080fd5b50565b6000813590506106a881610682565b92915050565b6000602082840312156106c4576106c361066d565b5b60006106d284828501610699565b91505092915050565b6000819050919050565b6106ee816106db565b82525050565b600060208201905061070960008301846106e5565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061075461074f61074a8461070f565b61072f565b61070f565b9050919050565b600061076682610739565b9050919050565b60006107788261075b565b9050919050565b6107888161076d565b82525050565b60006020820190506107a3600083018461077f565b92915050565b600067ffffffffffffffff82169050919050565b6107c6816107a9565b81146107d157600080fd5b50565b6000813590506107e3816107bd565b92915050565b6107f2816106db565b81146107fd57600080fd5b50565b60008135905061080f816107e9565b92915050565b60008115159050919050565b61082a81610815565b811461083557600080fd5b50565b60008135905061084781610821565b92915050565b600080600080600060a086880312156108695761086861066d565b5b600061087788828901610699565b9550506020610888888289016107d4565b945050604061089988828901610800565b93505060606108aa88828901610800565b92505060806108bb88828901610838565b9150509295509295909350565b6108d181610672565b82525050565b60006020820190506108ec60008301846108c8565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061096582610921565b915061097083610921565b92508282019050808211156109885761098761092b565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006109c882610921565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036109fa576109f961092b565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000610a3f82610921565b9150610a4a83610921565b925082610a5a57610a59610a05565b5b828206905092915050565b6000610a7082610921565b9150610a7b83610921565b925082610a8b57610a8a610a05565b5b828204905092915050565b6000610aa182610921565b9150610aac83610921565b9250828203905081811115610ac457610ac361092b565b5b92915050565b6000610ad582610921565b9150610ae083610921565b9250828202610aee81610921565b91508282048414831517610b0557610b0461092b565b5b5092915050565b6000819050919050565b610b27610b22826106db565b610b0c565b82525050565b6000610b398285610b16565b602082019150610b498284610b16565b6020820191508190509392505050565b6000610b6482610921565b915060008203610b7757610b7661092b565b5b600182039050919050565b610b8b816107a9565b82525050565b6000606082019050610ba66000830186610b82565b610bb360208301856106e5565b610bc060408301846106e5565b94935050505056fea2646970667358221220638bb76fb15c02bf12ba8ed137eb377ccf7928acb4bfb7cf7d3aeb9c24f9163564736f6c63430008120033 \ No newline at end of file +60a060405234801561001057600080fd5b5060405161082938038061082983398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b60805161079861009160003960008181609c01526104e301526107986000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80630680cf5c1461005c578063a2967d991461008f578063d02103ca14610097578063db3abdb9146100d6578063f4e92675146100eb575b600080fd5b61007c61006a3660046105de565b60016020526000908152604090205481565b6040519081526020015b60405180910390f35b61007c610110565b6100be7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610086565b6100e96100e4366004610600565b610499565b005b6000546100fb9063ffffffff1681565b60405163ffffffff9091168152602001610086565b6000805463ffffffff1680820361012957506000919050565b60008167ffffffffffffffff8111156101445761014461066f565b60405190808252806020026020018201604052801561016d578160200160208202803683370190505b50905060005b828110156101d35760016000610189838361069b565b63ffffffff1663ffffffff168152602001908152602001600020548282815181106101b6576101b66106b4565b6020908102919091010152806101cb816106ca565b915050610173565b50600060205b836001146103fd5760006101ee6002866106f9565b6101f960028761070d565b610203919061069b565b905060008167ffffffffffffffff8111156102205761022061066f565b604051908082528060200260200182016040528015610249578160200160208202803683370190505b50905060005b828110156103ad57610262600184610721565b8114801561027a57506102766002886106f9565b6001145b156102f7578561028b826002610734565b8151811061029b5761029b6106b4565b6020026020010151856040516020016102be929190918252602082015260400190565b604051602081830303815290604052805190602001208282815181106102e6576102e66106b4565b60200260200101818152505061039b565b85610303826002610734565b81518110610313576103136106b4565b6020026020010151868260026103299190610734565b61033490600161069b565b81518110610344576103446106b4565b6020026020010151604051602001610366929190918252602082015260400190565b6040516020818303038152906040528051906020012082828151811061038e5761038e6106b4565b6020026020010181815250505b806103a5816106ca565b91505061024f565b5080945081955083846040516020016103d0929190918252602082015260400190565b60405160208183030381529060405280519060200120935082806103f39061074b565b93505050506101d9565b600083600081518110610412576104126106b4565b6020026020010151905060005b8281101561048f57604080516020810184905290810185905260600160408051601f19818403018152828252805160209182012090830187905290820186905292506060016040516020818303038152906040528051906020012093508080610487906106ca565b91505061041f565b5095945050505050565b60005463ffffffff90811690861611156104c3576000805463ffffffff191663ffffffff87161790555b63ffffffff851660009081526001602052604090208390558015610569577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166333d6247d610518610110565b6040518263ffffffff1660e01b815260040161053691815260200190565b600060405180830381600087803b15801561055057600080fd5b505af1158015610564573d6000803e3d6000fd5b505050505b6040805167ffffffffffffffff8616815260208101849052908101849052339063ffffffff8716907faac1e7a157b259544ebacd6e8a82ae5d6c8f174e12aa48696277bcc9a661f0b49060600160405180910390a35050505050565b803563ffffffff811681146105d957600080fd5b919050565b6000602082840312156105f057600080fd5b6105f9826105c5565b9392505050565b600080600080600060a0868803121561061857600080fd5b610621866105c5565b9450602086013567ffffffffffffffff8116811461063e57600080fd5b935060408601359250606086013591506080860135801515811461066157600080fd5b809150509295509295909350565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156106ae576106ae610685565b92915050565b634e487b7160e01b600052603260045260246000fd5b6000600182016106dc576106dc610685565b5060010190565b634e487b7160e01b600052601260045260246000fd5b600082610708576107086106e3565b500690565b60008261071c5761071c6106e3565b500490565b818103818111156106ae576106ae610685565b80820281158282048414176106ae576106ae610685565b60008161075a5761075a610685565b50600019019056fea26469706673582212205adc139a1c2a423d3d8d0db882b69ac1b5cdcb3419bc6315ca33eeac9aa68a7464736f6c63430008120033 \ No newline at end of file diff --git a/test/contracts/claimmockcaller/ClaimMockCaller.sol b/test/contracts/claimmockcaller/ClaimMockCaller.sol index 914eecbd..3ab2f286 100644 --- a/test/contracts/claimmockcaller/ClaimMockCaller.sol +++ b/test/contracts/claimmockcaller/ClaimMockCaller.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.20; +pragma solidity 0.8.18; interface IClaimMock { diff --git a/test/contracts/claimmockcaller/claimmockcaller.go b/test/contracts/claimmockcaller/claimmockcaller.go index d0dc38eb..78acccad 100644 --- a/test/contracts/claimmockcaller/claimmockcaller.go +++ b/test/contracts/claimmockcaller/claimmockcaller.go @@ -32,7 +32,7 @@ var ( // ClaimmockcallerMetaData contains all meta data concerning the Claimmockcaller contract. var ClaimmockcallerMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"contractIClaimMock\",\"name\":\"_claimMock\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofLocalExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofRollupExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"uint256\",\"name\":\"globalIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"mainnetExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"rollupExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"originNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"destinationNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"name\":\"claimAsset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofLocalExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofRollupExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"uint256\",\"name\":\"globalIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"mainnetExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"rollupExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"originNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"destinationNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"name\":\"claimMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimMock\",\"outputs\":[{\"internalType\":\"contractIClaimMock\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b5060405161050238038061050283398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b60805161046b61009760003960008181604b0152818160fb01526101c3015261046b6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806383f5b00614610046578063ccaa2d1114610096578063f5efcd79146100ab575b600080fd5b61006d7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100a96100a4366004610263565b6100be565b005b6100a96100b9366004610263565b610186565b6040517fccaa2d1100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063ccaa2d1190610146908f908f908f908f908f908f908f908f908f908f908f908f9060040161036b565b600060405180830381600087803b15801561016057600080fd5b505af1158015610174573d6000803e3d6000fd5b50505050505050505050505050505050565b6040517ff5efcd7900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f5efcd7990610146908f908f908f908f908f908f908f908f908f908f908f908f9060040161036b565b80610400810183101561022057600080fd5b92915050565b803563ffffffff8116811461023a57600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461023a57600080fd5b6000806000806000806000806000806000806109208d8f03121561028657600080fd5b6102908e8e61020e565b9b506102a08e6104008f0161020e565b9a506108008d013599506108208d013598506108408d013597506102c76108608e01610226565b96506102d66108808e0161023f565b95506102e56108a08e01610226565b94506102f46108c08e0161023f565b93506108e08d013592506109008d013567ffffffffffffffff8082111561031a57600080fd5b818f0191508f601f83011261032e57600080fd5b808235111561033c57600080fd5b508e60208235830101111561035057600080fd5b60208101925080359150509295989b509295989b509295989b565b6000610400808f8437808e82850137508b6108008301528a6108208301528961084083015263ffffffff808a1661086084015273ffffffffffffffffffffffffffffffffffffffff808a166108808501528189166108a08501528088166108c08501525050846108e0830152610920610900830152826109208301526109408385828501376000838501820152601f9093017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169091019091019c9b50505050505050505050505056fea26469706673582212206727c3a78a95fb986d1a4568ebb299bd4398120ac4cd67a415f2c5c02e5ee78f64736f6c63430008140033", + Bin: "0x60a060405234801561001057600080fd5b5060405161047238038061047283398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b6080516103db61009760003960008181604b0152818160c8015261016a01526103db6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806383f5b00614610046578063ccaa2d1114610089578063f5efcd791461009e575b600080fd5b61006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61009c6100973660046101fd565b6100b1565b005b61009c6100ac3660046101fd565b610153565b60405163ccaa2d1160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ccaa2d1190610113908f908f908f908f908f908f908f908f908f908f908f908f90600401610305565b600060405180830381600087803b15801561012d57600080fd5b505af1158015610141573d6000803e3d6000fd5b50505050505050505050505050505050565b60405163f5efcd7960e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f5efcd7990610113908f908f908f908f908f908f908f908f908f908f908f908f90600401610305565b8061040081018310156101c757600080fd5b92915050565b803563ffffffff811681146101e157600080fd5b919050565b80356001600160a01b03811681146101e157600080fd5b6000806000806000806000806000806000806109208d8f03121561022057600080fd5b61022a8e8e6101b5565b9b5061023a8e6104008f016101b5565b9a506108008d013599506108208d013598506108408d013597506102616108608e016101cd565b96506102706108808e016101e6565b955061027f6108a08e016101cd565b945061028e6108c08e016101e6565b93506108e08d013592506109008d013567ffffffffffffffff808211156102b457600080fd5b818f0191508f601f8301126102c857600080fd5b80823511156102d657600080fd5b508e6020823583010111156102ea57600080fd5b60208101925080359150509295989b509295989b509295989b565b6000610400808f8437808e828501375061080082018c905261082082018b905261084082018a905263ffffffff8981166108608401526001600160a01b038981166108808501529088166108a084015286166108c08301526108e08201859052610920610900830181905282018390526109408385828501376000838501820152601f909301601f19169091019091019c9b50505050505050505050505056fea26469706673582212202321216f86560e0f29df639adc8713b3ce119002b4def8923caee0576ed8380564736f6c63430008120033", } // ClaimmockcallerABI is the input ABI used to generate the binding from. diff --git a/test/contracts/compile.sh b/test/contracts/compile.sh old mode 100644 new mode 100755 index 642cb4ad..d4f423e8 --- a/test/contracts/compile.sh +++ b/test/contracts/compile.sh @@ -1 +1,17 @@ -docker run --rm -v $(pwd):/contracts ethereum/solc:0.8.18-alpine - /contracts/verifybatchesmock/VerifyBatchesMock.sol -o /contracts --abi --bin --overwrite \ No newline at end of file +docker run --rm -v $(pwd):/contracts ethereum/solc:0.8.18-alpine - /contracts/verifybatchesmock/VerifyBatchesMock.sol -o /contracts --abi --bin --overwrite --optimize +mv -f VerifyBatchesMock.abi abi/verifybatchesmock.abi +mv -f VerifyBatchesMock.bin bin/verifybatchesmock.bin +rm -f IBasePolygonZkEVMGlobalExitRoot.abi +rm -f IBasePolygonZkEVMGlobalExitRoot.bin +rm -f IPolygonZkEVMGlobalExitRootV2.abi +rm -f IPolygonZkEVMGlobalExitRootV2.bin + +docker run --rm -v $(pwd):/contracts ethereum/solc:0.8.18-alpine - /contracts/claimmock/ClaimMock.sol -o /contracts --abi --bin --overwrite --optimize +mv -f ClaimMock.abi abi/claimmock.abi +mv -f ClaimMock.bin bin/claimmock.bin + +docker run --rm -v $(pwd):/contracts ethereum/solc:0.8.18-alpine - /contracts/claimmockcaller/ClaimMockCaller.sol -o /contracts --abi --bin --overwrite --optimize +mv -f ClaimMockCaller.abi abi/claimmockcaller.abi +mv -f ClaimMockCaller.bin bin/claimmockcaller.bin +rm -f IClaimMock.abi +rm -f IClaimMock.bin \ No newline at end of file diff --git a/test/contracts/verifybatchesmock/verifybatchesmock.go b/test/contracts/verifybatchesmock/verifybatchesmock.go index c3013f66..10fc3b8d 100644 --- a/test/contracts/verifybatchesmock/verifybatchesmock.go +++ b/test/contracts/verifybatchesmock/verifybatchesmock.go @@ -32,7 +32,7 @@ var ( // VerifybatchesmockMetaData contains all meta data concerning the Verifybatchesmock contract. var VerifybatchesmockMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"contractIPolygonZkEVMGlobalExitRootV2\",\"name\":\"_globalExitRootManager\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"rollupID\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"numBatch\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"exitRoot\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"VerifyBatches\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getRollupExitRoot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"globalExitRootManager\",\"outputs\":[{\"internalType\":\"contractIPolygonZkEVMGlobalExitRootV2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupCount\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rollupID\",\"type\":\"uint32\"}],\"name\":\"rollupIDToLastExitRoot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"rollupID\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"finalNewBatch\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"newLocalExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"newStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"updateGER\",\"type\":\"bool\"}],\"name\":\"verifyBatches\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b50604051610d2e380380610d2e833981810160405281019061003291906100e1565b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250505061010e565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061009c82610071565b9050919050565b60006100ae82610091565b9050919050565b6100be816100a3565b81146100c957600080fd5b50565b6000815190506100db816100b5565b92915050565b6000602082840312156100f7576100f661006c565b5b6000610105848285016100cc565b91505092915050565b608051610bfe610130600039600081816104d501526105680152610bfe6000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80630680cf5c1461005c578063a2967d991461008c578063d02103ca146100aa578063db3abdb9146100c8578063f4e92675146100e4575b600080fd5b610076600480360381019061007191906106ae565b610102565b60405161008391906106f4565b60405180910390f35b61009461011a565b6040516100a191906106f4565b60405180910390f35b6100b26104d3565b6040516100bf919061078e565b60405180910390f35b6100e260048036038101906100dd919061084d565b6104f7565b005b6100ec610659565b6040516100f991906108d7565b60405180910390f35b60016020528060005260406000206000915090505481565b60008060008054906101000a900463ffffffff1663ffffffff1690506000810361014a576000801b9150506104d0565b60008167ffffffffffffffff811115610166576101656108f2565b5b6040519080825280602002602001820160405280156101945781602001602082028036833780820191505090505b50905060005b8281101561020057600160006001836101b3919061095a565b63ffffffff1663ffffffff168152602001908152602001600020548282815181106101e1576101e061098e565b5b60200260200101818152505080806101f8906109bd565b91505061019a565b5060008060001b90506000602090505b600184146104325760006002856102279190610a34565b6002866102349190610a65565b61023e919061095a565b905060008167ffffffffffffffff81111561025c5761025b6108f2565b5b60405190808252806020026020018201604052801561028a5781602001602082028036833780820191505090505b50905060005b828110156103eb576001836102a59190610a96565b811480156102bf575060016002886102bd9190610a34565b145b1561033757856002826102d29190610aca565b815181106102e3576102e261098e565b5b6020026020010151856040516020016102fd929190610b2d565b604051602081830303815290604052805190602001208282815181106103265761032561098e565b5b6020026020010181815250506103d8565b856002826103459190610aca565b815181106103565761035561098e565b5b602002602001015186600160028461036e9190610aca565b610378919061095a565b815181106103895761038861098e565b5b60200260200101516040516020016103a2929190610b2d565b604051602081830303815290604052805190602001208282815181106103cb576103ca61098e565b5b6020026020010181815250505b80806103e3906109bd565b915050610290565b508094508195508384604051602001610405929190610b2d565b604051602081830303815290604052805190602001209350828061042890610b59565b9350505050610210565b6000836000815181106104485761044761098e565b5b6020026020010151905060005b828110156104c6578184604051602001610470929190610b2d565b604051602081830303815290604052805190602001209150838460405160200161049b929190610b2d565b60405160208183030381529060405280519060200120935080806104be906109bd565b915050610455565b5080955050505050505b90565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008054906101000a900463ffffffff1663ffffffff168563ffffffff16111561053c57846000806101000a81548163ffffffff021916908363ffffffff1602179055505b82600160008763ffffffff1663ffffffff1681526020019081526020016000208190555080156105f9577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166333d6247d6105aa61011a565b6040518263ffffffff1660e01b81526004016105c691906106f4565b600060405180830381600087803b1580156105e057600080fd5b505af11580156105f4573d6000803e3d6000fd5b505050505b3373ffffffffffffffffffffffffffffffffffffffff168563ffffffff167faac1e7a157b259544ebacd6e8a82ae5d6c8f174e12aa48696277bcc9a661f0b486858760405161064a93929190610b91565b60405180910390a35050505050565b60008054906101000a900463ffffffff1681565b600080fd5b600063ffffffff82169050919050565b61068b81610672565b811461069657600080fd5b50565b6000813590506106a881610682565b92915050565b6000602082840312156106c4576106c361066d565b5b60006106d284828501610699565b91505092915050565b6000819050919050565b6106ee816106db565b82525050565b600060208201905061070960008301846106e5565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061075461074f61074a8461070f565b61072f565b61070f565b9050919050565b600061076682610739565b9050919050565b60006107788261075b565b9050919050565b6107888161076d565b82525050565b60006020820190506107a3600083018461077f565b92915050565b600067ffffffffffffffff82169050919050565b6107c6816107a9565b81146107d157600080fd5b50565b6000813590506107e3816107bd565b92915050565b6107f2816106db565b81146107fd57600080fd5b50565b60008135905061080f816107e9565b92915050565b60008115159050919050565b61082a81610815565b811461083557600080fd5b50565b60008135905061084781610821565b92915050565b600080600080600060a086880312156108695761086861066d565b5b600061087788828901610699565b9550506020610888888289016107d4565b945050604061089988828901610800565b93505060606108aa88828901610800565b92505060806108bb88828901610838565b9150509295509295909350565b6108d181610672565b82525050565b60006020820190506108ec60008301846108c8565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061096582610921565b915061097083610921565b92508282019050808211156109885761098761092b565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006109c882610921565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036109fa576109f961092b565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000610a3f82610921565b9150610a4a83610921565b925082610a5a57610a59610a05565b5b828206905092915050565b6000610a7082610921565b9150610a7b83610921565b925082610a8b57610a8a610a05565b5b828204905092915050565b6000610aa182610921565b9150610aac83610921565b9250828203905081811115610ac457610ac361092b565b5b92915050565b6000610ad582610921565b9150610ae083610921565b9250828202610aee81610921565b91508282048414831517610b0557610b0461092b565b5b5092915050565b6000819050919050565b610b27610b22826106db565b610b0c565b82525050565b6000610b398285610b16565b602082019150610b498284610b16565b6020820191508190509392505050565b6000610b6482610921565b915060008203610b7757610b7661092b565b5b600182039050919050565b610b8b816107a9565b82525050565b6000606082019050610ba66000830186610b82565b610bb360208301856106e5565b610bc060408301846106e5565b94935050505056fea2646970667358221220638bb76fb15c02bf12ba8ed137eb377ccf7928acb4bfb7cf7d3aeb9c24f9163564736f6c63430008120033", + Bin: "0x60a060405234801561001057600080fd5b5060405161082938038061082983398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b60805161079861009160003960008181609c01526104e301526107986000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80630680cf5c1461005c578063a2967d991461008f578063d02103ca14610097578063db3abdb9146100d6578063f4e92675146100eb575b600080fd5b61007c61006a3660046105de565b60016020526000908152604090205481565b6040519081526020015b60405180910390f35b61007c610110565b6100be7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610086565b6100e96100e4366004610600565b610499565b005b6000546100fb9063ffffffff1681565b60405163ffffffff9091168152602001610086565b6000805463ffffffff1680820361012957506000919050565b60008167ffffffffffffffff8111156101445761014461066f565b60405190808252806020026020018201604052801561016d578160200160208202803683370190505b50905060005b828110156101d35760016000610189838361069b565b63ffffffff1663ffffffff168152602001908152602001600020548282815181106101b6576101b66106b4565b6020908102919091010152806101cb816106ca565b915050610173565b50600060205b836001146103fd5760006101ee6002866106f9565b6101f960028761070d565b610203919061069b565b905060008167ffffffffffffffff8111156102205761022061066f565b604051908082528060200260200182016040528015610249578160200160208202803683370190505b50905060005b828110156103ad57610262600184610721565b8114801561027a57506102766002886106f9565b6001145b156102f7578561028b826002610734565b8151811061029b5761029b6106b4565b6020026020010151856040516020016102be929190918252602082015260400190565b604051602081830303815290604052805190602001208282815181106102e6576102e66106b4565b60200260200101818152505061039b565b85610303826002610734565b81518110610313576103136106b4565b6020026020010151868260026103299190610734565b61033490600161069b565b81518110610344576103446106b4565b6020026020010151604051602001610366929190918252602082015260400190565b6040516020818303038152906040528051906020012082828151811061038e5761038e6106b4565b6020026020010181815250505b806103a5816106ca565b91505061024f565b5080945081955083846040516020016103d0929190918252602082015260400190565b60405160208183030381529060405280519060200120935082806103f39061074b565b93505050506101d9565b600083600081518110610412576104126106b4565b6020026020010151905060005b8281101561048f57604080516020810184905290810185905260600160408051601f19818403018152828252805160209182012090830187905290820186905292506060016040516020818303038152906040528051906020012093508080610487906106ca565b91505061041f565b5095945050505050565b60005463ffffffff90811690861611156104c3576000805463ffffffff191663ffffffff87161790555b63ffffffff851660009081526001602052604090208390558015610569577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166333d6247d610518610110565b6040518263ffffffff1660e01b815260040161053691815260200190565b600060405180830381600087803b15801561055057600080fd5b505af1158015610564573d6000803e3d6000fd5b505050505b6040805167ffffffffffffffff8616815260208101849052908101849052339063ffffffff8716907faac1e7a157b259544ebacd6e8a82ae5d6c8f174e12aa48696277bcc9a661f0b49060600160405180910390a35050505050565b803563ffffffff811681146105d957600080fd5b919050565b6000602082840312156105f057600080fd5b6105f9826105c5565b9392505050565b600080600080600060a0868803121561061857600080fd5b610621866105c5565b9450602086013567ffffffffffffffff8116811461063e57600080fd5b935060408601359250606086013591506080860135801515811461066157600080fd5b809150509295509295909350565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156106ae576106ae610685565b92915050565b634e487b7160e01b600052603260045260246000fd5b6000600182016106dc576106dc610685565b5060010190565b634e487b7160e01b600052601260045260246000fd5b600082610708576107086106e3565b500690565b60008261071c5761071c6106e3565b500490565b818103818111156106ae576106ae610685565b80820281158282048414176106ae576106ae610685565b60008161075a5761075a610685565b50600019019056fea26469706673582212205adc139a1c2a423d3d8d0db882b69ac1b5cdcb3419bc6315ca33eeac9aa68a7464736f6c63430008120033", } // VerifybatchesmockABI is the input ABI used to generate the binding from. From f3d4af64d3190b7815eeef6475397bc780b8e122 Mon Sep 17 00:00:00 2001 From: bros Date: Fri, 30 Aug 2024 13:53:56 +0000 Subject: [PATCH 07/31] fix building contract scripts --- test/contracts/abi/claimmock.abi | 166 +------------------------ test/contracts/bin/claimmock.bin | 2 +- test/contracts/claimmock/ClaimMock.sol | 2 +- test/contracts/claimmock/claimmock.go | 2 +- 4 files changed, 4 insertions(+), 168 deletions(-) diff --git a/test/contracts/abi/claimmock.abi b/test/contracts/abi/claimmock.abi index e7a51225..2b75f658 100644 --- a/test/contracts/abi/claimmock.abi +++ b/test/contracts/abi/claimmock.abi @@ -1,165 +1 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "globalIndex", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint32", - "name": "originNetwork", - "type": "uint32" - }, - { - "indexed": false, - "internalType": "address", - "name": "originAddress", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "destinationAddress", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ClaimEvent", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "bytes32[32]", - "name": "smtProofLocalExitRoot", - "type": "bytes32[32]" - }, - { - "internalType": "bytes32[32]", - "name": "smtProofRollupExitRoot", - "type": "bytes32[32]" - }, - { - "internalType": "uint256", - "name": "globalIndex", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "mainnetExitRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "rollupExitRoot", - "type": "bytes32" - }, - { - "internalType": "uint32", - "name": "originNetwork", - "type": "uint32" - }, - { - "internalType": "address", - "name": "originTokenAddress", - "type": "address" - }, - { - "internalType": "uint32", - "name": "destinationNetwork", - "type": "uint32" - }, - { - "internalType": "address", - "name": "destinationAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "metadata", - "type": "bytes" - } - ], - "name": "claimAsset", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32[32]", - "name": "smtProofLocalExitRoot", - "type": "bytes32[32]" - }, - { - "internalType": "bytes32[32]", - "name": "smtProofRollupExitRoot", - "type": "bytes32[32]" - }, - { - "internalType": "uint256", - "name": "globalIndex", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "mainnetExitRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "rollupExitRoot", - "type": "bytes32" - }, - { - "internalType": "uint32", - "name": "originNetwork", - "type": "uint32" - }, - { - "internalType": "address", - "name": "originAddress", - "type": "address" - }, - { - "internalType": "uint32", - "name": "destinationNetwork", - "type": "uint32" - }, - { - "internalType": "address", - "name": "destinationAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "metadata", - "type": "bytes" - } - ], - "name": "claimMessage", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ] \ No newline at end of file +[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"globalIndex","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"originNetwork","type":"uint32"},{"indexed":false,"internalType":"address","name":"originAddress","type":"address"},{"indexed":false,"internalType":"address","name":"destinationAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimEvent","type":"event"},{"inputs":[{"internalType":"bytes32[32]","name":"smtProofLocalExitRoot","type":"bytes32[32]"},{"internalType":"bytes32[32]","name":"smtProofRollupExitRoot","type":"bytes32[32]"},{"internalType":"uint256","name":"globalIndex","type":"uint256"},{"internalType":"bytes32","name":"mainnetExitRoot","type":"bytes32"},{"internalType":"bytes32","name":"rollupExitRoot","type":"bytes32"},{"internalType":"uint32","name":"originNetwork","type":"uint32"},{"internalType":"address","name":"originTokenAddress","type":"address"},{"internalType":"uint32","name":"destinationNetwork","type":"uint32"},{"internalType":"address","name":"destinationAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"claimAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[32]","name":"smtProofLocalExitRoot","type":"bytes32[32]"},{"internalType":"bytes32[32]","name":"smtProofRollupExitRoot","type":"bytes32[32]"},{"internalType":"uint256","name":"globalIndex","type":"uint256"},{"internalType":"bytes32","name":"mainnetExitRoot","type":"bytes32"},{"internalType":"bytes32","name":"rollupExitRoot","type":"bytes32"},{"internalType":"uint32","name":"originNetwork","type":"uint32"},{"internalType":"address","name":"originAddress","type":"address"},{"internalType":"uint32","name":"destinationNetwork","type":"uint32"},{"internalType":"address","name":"destinationAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"claimMessage","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/test/contracts/bin/claimmock.bin b/test/contracts/bin/claimmock.bin index bbde9978..62d961e8 100644 --- a/test/contracts/bin/claimmock.bin +++ b/test/contracts/bin/claimmock.bin @@ -1 +1 @@ -608060405234801561001057600080fd5b5061025a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063ccaa2d111461003b578063f5efcd791461003b575b600080fd5b61004e61004936600461011c565b610050565b005b604080518b815263ffffffff8916602082015273ffffffffffffffffffffffffffffffffffffffff88811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b8061040081018310156100d957600080fd5b92915050565b803563ffffffff811681146100f357600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146100f357600080fd5b6000806000806000806000806000806000806109208d8f03121561013f57600080fd5b6101498e8e6100c7565b9b506101598e6104008f016100c7565b9a506108008d013599506108208d013598506108408d013597506101806108608e016100df565b965061018f6108808e016100f8565b955061019e6108a08e016100df565b94506101ad6108c08e016100f8565b93506108e08d013592506109008d013567ffffffffffffffff808211156101d357600080fd5b818f0191508f601f8301126101e757600080fd5b80823511156101f557600080fd5b508e60208235830101111561020957600080fd5b60208101925080359150509295989b509295989b509295989b56fea26469706673582212201bdd4081435a27b9ab2f7421c2d1f3979d52c6cece33269bd75823a6e6a7fe2b64736f6c63430008140033 \ No newline at end of file +608060405234801561001057600080fd5b50610240806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063ccaa2d111461003b578063f5efcd791461003b575b600080fd5b61004e610049366004610102565b610050565b005b604080518b815263ffffffff891660208201526001600160a01b0388811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b8061040081018310156100cc57600080fd5b92915050565b803563ffffffff811681146100e657600080fd5b919050565b80356001600160a01b03811681146100e657600080fd5b6000806000806000806000806000806000806109208d8f03121561012557600080fd5b61012f8e8e6100ba565b9b5061013f8e6104008f016100ba565b9a506108008d013599506108208d013598506108408d013597506101666108608e016100d2565b96506101756108808e016100eb565b95506101846108a08e016100d2565b94506101936108c08e016100eb565b93506108e08d013592506109008d013567ffffffffffffffff808211156101b957600080fd5b818f0191508f601f8301126101cd57600080fd5b80823511156101db57600080fd5b508e6020823583010111156101ef57600080fd5b60208101925080359150509295989b509295989b509295989b56fea2646970667358221220ea3ccb4fef38083776607b84bdd7b00012029d7d1fee9fa7c300663fe761dcac64736f6c63430008120033 \ No newline at end of file diff --git a/test/contracts/claimmock/ClaimMock.sol b/test/contracts/claimmock/ClaimMock.sol index cb609eae..14d94eae 100644 --- a/test/contracts/claimmock/ClaimMock.sol +++ b/test/contracts/claimmock/ClaimMock.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.20; +pragma solidity 0.8.18; contract ClaimMock { uint8 constant _DEPOSIT_CONTRACT_TREE_DEPTH = 32; diff --git a/test/contracts/claimmock/claimmock.go b/test/contracts/claimmock/claimmock.go index dacd0458..cc577908 100644 --- a/test/contracts/claimmock/claimmock.go +++ b/test/contracts/claimmock/claimmock.go @@ -32,7 +32,7 @@ var ( // ClaimmockMetaData contains all meta data concerning the Claimmock contract. var ClaimmockMetaData = &bind.MetaData{ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"globalIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originNetwork\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ClaimEvent\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofLocalExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofRollupExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"uint256\",\"name\":\"globalIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"mainnetExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"rollupExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"originNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"destinationNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"name\":\"claimAsset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofLocalExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"bytes32[32]\",\"name\":\"smtProofRollupExitRoot\",\"type\":\"bytes32[32]\"},{\"internalType\":\"uint256\",\"name\":\"globalIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"mainnetExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"rollupExitRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"originNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"destinationNetwork\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"name\":\"claimMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b5061025a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063ccaa2d111461003b578063f5efcd791461003b575b600080fd5b61004e61004936600461011c565b610050565b005b604080518b815263ffffffff8916602082015273ffffffffffffffffffffffffffffffffffffffff88811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b8061040081018310156100d957600080fd5b92915050565b803563ffffffff811681146100f357600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146100f357600080fd5b6000806000806000806000806000806000806109208d8f03121561013f57600080fd5b6101498e8e6100c7565b9b506101598e6104008f016100c7565b9a506108008d013599506108208d013598506108408d013597506101806108608e016100df565b965061018f6108808e016100f8565b955061019e6108a08e016100df565b94506101ad6108c08e016100f8565b93506108e08d013592506109008d013567ffffffffffffffff808211156101d357600080fd5b818f0191508f601f8301126101e757600080fd5b80823511156101f557600080fd5b508e60208235830101111561020957600080fd5b60208101925080359150509295989b509295989b509295989b56fea26469706673582212201bdd4081435a27b9ab2f7421c2d1f3979d52c6cece33269bd75823a6e6a7fe2b64736f6c63430008140033", + Bin: "0x608060405234801561001057600080fd5b50610240806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063ccaa2d111461003b578063f5efcd791461003b575b600080fd5b61004e610049366004610102565b610050565b005b604080518b815263ffffffff891660208201526001600160a01b0388811682840152861660608201526080810185905290517f1df3f2a973a00d6635911755c260704e95e8a5876997546798770f76396fda4d9181900360a00190a1505050505050505050505050565b8061040081018310156100cc57600080fd5b92915050565b803563ffffffff811681146100e657600080fd5b919050565b80356001600160a01b03811681146100e657600080fd5b6000806000806000806000806000806000806109208d8f03121561012557600080fd5b61012f8e8e6100ba565b9b5061013f8e6104008f016100ba565b9a506108008d013599506108208d013598506108408d013597506101666108608e016100d2565b96506101756108808e016100eb565b95506101846108a08e016100d2565b94506101936108c08e016100eb565b93506108e08d013592506109008d013567ffffffffffffffff808211156101b957600080fd5b818f0191508f601f8301126101cd57600080fd5b80823511156101db57600080fd5b508e6020823583010111156101ef57600080fd5b60208101925080359150509295989b509295989b509295989b56fea2646970667358221220ea3ccb4fef38083776607b84bdd7b00012029d7d1fee9fa7c300663fe761dcac64736f6c63430008120033", } // ClaimmockABI is the input ABI used to generate the binding from. From 9ea9b294d39de730f8a7a4bce0c276fea2fa2cec Mon Sep 17 00:00:00 2001 From: bros Date: Fri, 30 Aug 2024 15:40:27 +0000 Subject: [PATCH 08/31] wip --- bridgesync/migrations/0001.sql | 49 ++++++++++++++++ bridgesync/migrations/migrations.go | 25 +++++++++ bridgesync/processor.go | 20 +++---- db/config.go | 25 +++++++++ db/logger.go | 27 +++++++++ db/migrations.go | 87 +++++++++++++++++++++++++++++ db/sqlite.go | 27 +++++++++ go.mod | 13 ++++- go.sum | 25 +++++++++ 9 files changed, 287 insertions(+), 11 deletions(-) create mode 100644 bridgesync/migrations/0001.sql create mode 100644 bridgesync/migrations/migrations.go create mode 100644 db/config.go create mode 100644 db/logger.go create mode 100644 db/migrations.go create mode 100644 db/sqlite.go diff --git a/bridgesync/migrations/0001.sql b/bridgesync/migrations/0001.sql new file mode 100644 index 00000000..ccffb729 --- /dev/null +++ b/bridgesync/migrations/0001.sql @@ -0,0 +1,49 @@ +-- +migrate Down +DROP SCHEMA IF EXISTS bridge CASCADE; + +-- +migrate Up +CREATE SCHEMA bridge; + +CREATE TABLE bridge.index +( + index_num BIGINT PRIMARY KEY, +); + +CREATE TABLE bridge.claim +( + index_num INTEGER NOT NULL REFERENCES bridge.index (index_num) ON DELETE CASCADE, + index_pos INTEGER NOT NULL, + + leaf_type INTEGER NOT NULL, + origin_network INTEGER NOT NULL, + origin_address VARCHAR NOT NULL, + destination_address INTEGER NOT NULL, + destination_address VARCHAR NOT NULL, + amount DECIMAL(78, 0) NOT NULL, + metadata BLOB, + deposit_count INTEGER NOT NULL, + + PRIMARY KEY (index_num, index_pos) +); + +CREATE TABLE bridge.bridge +( + index_num BIGINT NOT NULL REFERENCES bridge.index (index_num) ON DELETE CASCADE, + index_pos BIGINT NOT NULL, + + global_index DECIMAL(78, 0) NOT NULL, + origin_network INTEGER NOT NULL, + origin_address VARCHAR NOT NULL, + destination_address VARCHAR NOT NULL, + amount DECIMAL(78, 0) NOT NULL, + proof_local_exit_root VARCHAR, + proof_rollup_exit_root VARCHAR, + mainnet_exit_root VARCHAR, + rollup_exit_root VARCHAR, + global_exit_root VARCHAR, + destination_network INTEGER NOT NULL, + metadata BLOB, + is_message BOOLEAN, + + PRIMARY KEY (index_num, index_pos) +); \ No newline at end of file diff --git a/bridgesync/migrations/migrations.go b/bridgesync/migrations/migrations.go new file mode 100644 index 00000000..0aa85608 --- /dev/null +++ b/bridgesync/migrations/migrations.go @@ -0,0 +1,25 @@ +package migrations + +import ( + "strings" + + migrate "github.com/rubenv/sql-migrate" + + _ "embed" +) + +const upDownSeparator = "-- +migrate Up" + +//go:embed 0001.sql +var mig001 string +var mig001splitted = strings.Split(mig001, upDownSeparator) + +var Migrations = &migrate.MemoryMigrationSource{ + Migrations: []*migrate.Migration{ + { + Id: "001", + Up: []string{mig001splitted[1]}, + Down: []string{mig001splitted[0]}, + }, + }, +} diff --git a/bridgesync/processor.go b/bridgesync/processor.go index bd96732f..8f7c0798 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -2,6 +2,7 @@ package bridgesync import ( "context" + "database/sql" "encoding/binary" "encoding/json" "errors" @@ -15,6 +16,7 @@ import ( "github.com/iden3/go-iden3-crypto/keccak256" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/mdbx" + _ "modernc.org/sqlite" ) const ( @@ -93,7 +95,7 @@ type Event struct { } type processor struct { - db kv.RwDB + db *sql.DB eventsTable string lastBlockTable string exitTree *tree.AppendOnlyTree @@ -101,25 +103,23 @@ type processor struct { } func newProcessor(ctx context.Context, dbPath, dbPrefix string) (*processor, error) { + db, err := sql.Open("sqlite", dbPath) + if err != nil { + return nil, err + } eventsTable := dbPrefix + eventsTableSufix lastBlockTable := dbPrefix + lastBlockTableSufix logger := log.WithFields("bridge-syncer", dbPrefix) tableCfgFunc := func(defaultBuckets kv.TableCfg) kv.TableCfg { - cfg := kv.TableCfg{ - eventsTable: {}, - lastBlockTable: {}, - } + cfg := kv.TableCfg{} tree.AddTables(cfg, dbPrefix) return cfg } - db, err := mdbx.NewMDBX(nil). + treeDB, err := mdbx.NewMDBX(nil). Path(dbPath). WithTableCfg(tableCfgFunc). Open() - if err != nil { - return nil, err - } - exitTree, err := tree.NewAppendOnlyTree(ctx, db, dbPrefix) + exitTree, err := tree.NewAppendOnlyTree(ctx, treeDB, dbPrefix) if err != nil { return nil, err } diff --git a/db/config.go b/db/config.go new file mode 100644 index 00000000..ad56155f --- /dev/null +++ b/db/config.go @@ -0,0 +1,25 @@ +package db + +// Config provide fields to configure the pool +type Config struct { + // Database name + Name string `mapstructure:"Name"` + + // Database User name + User string `mapstructure:"User"` + + // Database Password of the user + Password string `mapstructure:"Password"` + + // Host address of database + Host string `mapstructure:"Host"` + + // Port Number of database + Port string `mapstructure:"Port"` + + // EnableLog + EnableLog bool `mapstructure:"EnableLog"` + + // MaxConns is the maximum number of connections in the pool. + MaxConns int `mapstructure:"MaxConns"` +} diff --git a/db/logger.go b/db/logger.go new file mode 100644 index 00000000..9478477f --- /dev/null +++ b/db/logger.go @@ -0,0 +1,27 @@ +package db + +import ( + "context" + + "github.com/jackc/pgx" +) + +type logger struct{} + +func (l logger) Log(ctx context.Context, level pgx.LogLevel, msg string, data map[string]interface{}) { + // TODO: adapt to sqlite + + // m := fmt.Sprintf("%s %v", msg, data) + + // switch level { + // case pgx.LogLevelInfo: + // log.Info(m) + // case pgx.LogLevelWarn: + // log.Warn(m) + // case pgx.LogLevelError: + // log.Error(m) + // default: + // m = fmt.Sprintf("%s %s %v", level.String(), msg, data) + // log.Debug(m) + // } +} diff --git a/db/migrations.go b/db/migrations.go new file mode 100644 index 00000000..ddc83680 --- /dev/null +++ b/db/migrations.go @@ -0,0 +1,87 @@ +package db + +import ( + "fmt" + + "github.com/0xPolygon/cdk/log" + "github.com/jackc/pgx/v4" + "github.com/jackc/pgx/v4/stdlib" + migrate "github.com/rubenv/sql-migrate" +) + +// RunMigrationsUp runs migrate-up for the given config. +func RunMigrationsUp(cfg Config, name string) error { + log.Info("running migrations up") + return runMigrations(cfg, name, migrate.Up) +} + +// CheckMigrations runs migrate-up for the given config. +func CheckMigrations(cfg Config, name string) error { + return checkMigrations(cfg, name, migrate.Up) +} + +// RunMigrationsDown runs migrate-down for the given config. +func RunMigrationsDown(cfg Config, name string) error { + log.Info("running migrations down") + return runMigrations(cfg, name, migrate.Down) +} + +// runMigrations will execute pending migrations if needed to keep +// the database updated with the latest changes in either direction, +// up or down. +func runMigrations(cfg Config, migrations migrate.MigrationSource, direction migrate.MigrationDirection) error { + c, err := pgx.ParseConfig(fmt.Sprintf("sqlite://%s:%s@%s:%s/%s", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Name)) + if err != nil { + return err + } + db := stdlib.OpenDB(*c) + + nMigrations, err := migrate.Exec(db, "sqlite", migrations, direction) + if err != nil { + return err + } + + log.Infof("successfully ran %d migrations", nMigrations) + return nil +} + +func checkMigrations(cfg Config, packrName string, direction migrate.MigrationDirection) error { + c, err := pgx.ParseConfig(fmt.Sprintf("postgres://%s:%s@%s:%s/%s", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Name)) + if err != nil { + return err + } + db := stdlib.OpenDB(*c) + + box, ok := packrMigrations[packrName] + if !ok { + return fmt.Errorf("packr box not found with name: %v", packrName) + } + + migrationSource := &migrate.PackrMigrationSource{Box: box} + migrations, err := migrationSource.FindMigrations() + if err != nil { + log.Errorf("error getting migrations from source: %v", err) + return err + } + + var expected int + for _, migration := range migrations { + if len(migration.Up) != 0 { + expected++ + } + } + + var actual int + query := `SELECT COUNT(1) FROM public.gorp_migrations` + err = db.QueryRow(query).Scan(&actual) + if err != nil { + log.Error("error getting migrations count: ", err) + return err + } + if expected == actual { + log.Infof("Found %d migrations as expected", actual) + } else { + return fmt.Errorf("error the component needs to run %d migrations before starting. DB only contains %d migrations", expected, actual) + } + return nil +} diff --git a/db/sqlite.go b/db/sqlite.go new file mode 100644 index 00000000..75d28d0d --- /dev/null +++ b/db/sqlite.go @@ -0,0 +1,27 @@ +package db + +import ( + "context" + "fmt" + + "github.com/0xPolygon/cdk/log" + "github.com/jackc/pgx/v4/pgxpool" +) + +// NewSQLiteDB creates a new SQLite DB +func NewSQLiteDB(cfg Config) (*pgxpool.Pool, error) { + config, err := pgxpool.ParseConfig(fmt.Sprintf("postgres://%s:%s@%s:%s/%s?pool_max_conns=%d", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Name, cfg.MaxConns)) + if err != nil { + log.Errorf("Unable to parse DB config: %v\n", err) + return nil, err + } + if cfg.EnableLog { + config.ConnConfig.Logger = logger{} + } + conn, err := pgxpool.ConnectConfig(context.Background(), config) + if err != nil { + log.Errorf("Unable to connect to database: %v\n", err) + return nil, err + } + return conn, nil +} diff --git a/go.mod b/go.mod index dc65c9f9..5f1e0744 100644 --- a/go.mod +++ b/go.mod @@ -59,6 +59,7 @@ require ( github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/didip/tollbooth/v6 v6.1.2 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/erigontech/mdbx-go v0.27.14 // indirect github.com/ethereum/c-kzg-4844 v1.0.0 // indirect github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 // indirect @@ -79,6 +80,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.1 // indirect github.com/hashicorp/go-bexpr v0.1.10 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.1-0.20180906183839-65a6292f0157 // indirect github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect @@ -106,6 +108,7 @@ require ( github.com/miguelmota/go-solidity-sha3 v0.1.1 // indirect github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/onsi/gomega v1.27.10 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect @@ -116,6 +119,7 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rs/cors v1.7.0 // indirect @@ -142,12 +146,19 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/sys v0.24.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a // indirect + modernc.org/libc v1.60.0 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.8.0 // indirect + modernc.org/sqlite v1.32.0 // indirect + modernc.org/strutil v1.2.0 // indirect + modernc.org/token v1.1.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index bd4c8857..e7b35224 100644 --- a/go.sum +++ b/go.sum @@ -89,6 +89,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/didip/tollbooth/v6 v6.1.2 h1:Kdqxmqw9YTv0uKajBUiWQg+GURL/k4vy9gmLCL01PjQ= github.com/didip/tollbooth/v6 v6.1.2/go.mod h1:xjcse6CTHCLuOkzsWrEgdy9WPJFv+p/x6v+MyfP+O9s= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/erigontech/mdbx-go v0.27.14 h1:IVVeQVCAjZRpAR8bThlP2ISxrOwdV35NZdGwAgotaRw= github.com/erigontech/mdbx-go v0.27.14/go.mod h1:FAMxbOgqOnRDx51j8HjuJZIgznbDwjX7LItd+/UWyA4= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= @@ -174,6 +176,9 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDa github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.1-0.20180906183839-65a6292f0157 h1:uyodBE3xDz0ynKs1tLBU26wOQoEkAqqiY18DbZ+FZrA= github.com/hashicorp/hcl v1.0.1-0.20180906183839-65a6292f0157/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hermeznetwork/tracerr v0.3.2 h1:QB3TlQxO/4XHyixsg+nRZPuoel/FFQlQ7oAoHDD5l1c= @@ -308,6 +313,8 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -348,6 +355,8 @@ github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSz github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -526,6 +535,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -595,5 +606,19 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a h1:CfbpOLEo2IwNzJdMvE8aiRbPMxoTpgAJeyePh0SmO8M= +modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.60.0 h1:XeRF1gXky7JE5E8IErtYAdKj+ykZPdYUsgJNQ8RFWIA= +modernc.org/libc v1.60.0/go.mod h1:xJuobKuNxKH3RUatS7GjR+suWj+5c2K7bi4m/S5arOY= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s= +modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= From eac43c8c3b4a4c2049cd17b17a93f1b8b23325b4 Mon Sep 17 00:00:00 2001 From: bros Date: Mon, 2 Sep 2024 16:04:54 +0000 Subject: [PATCH 09/31] WIP --- bridgesync/migrations/0001.sql | 31 +++-- bridgesync/migrations/0001_test.go | 61 +++++++++ bridgesync/migrations/migrations.go | 5 + bridgesync/processor.go | 186 +++++++++++++++++++--------- db/migrations.go | 74 ++--------- db/sqlite.go | 23 +--- go.mod | 4 +- go.sum | 25 +++- tree/tree.go | 4 + 9 files changed, 249 insertions(+), 164 deletions(-) create mode 100644 bridgesync/migrations/0001_test.go diff --git a/bridgesync/migrations/0001.sql b/bridgesync/migrations/0001.sql index ccffb729..1901fb2d 100644 --- a/bridgesync/migrations/0001.sql +++ b/bridgesync/migrations/0001.sql @@ -1,35 +1,32 @@ -- +migrate Down -DROP SCHEMA IF EXISTS bridge CASCADE; +DROP TABLE IF EXISTS block; +DROP TABLE IF EXISTS claim; +DROP TABLE IF EXISTS bridge; -- +migrate Up -CREATE SCHEMA bridge; - -CREATE TABLE bridge.index -( - index_num BIGINT PRIMARY KEY, +CREATE TABLE block ( + num BIGINT PRIMARY KEY ); -CREATE TABLE bridge.claim -( - index_num INTEGER NOT NULL REFERENCES bridge.index (index_num) ON DELETE CASCADE, - index_pos INTEGER NOT NULL, +CREATE TABLE claim ( + block_num INTEGER NOT NULL REFERENCES block (num) ON DELETE CASCADE, + block_pos INTEGER NOT NULL, leaf_type INTEGER NOT NULL, origin_network INTEGER NOT NULL, origin_address VARCHAR NOT NULL, - destination_address INTEGER NOT NULL, + destination_network INTEGER NOT NULL, destination_address VARCHAR NOT NULL, amount DECIMAL(78, 0) NOT NULL, metadata BLOB, deposit_count INTEGER NOT NULL, - PRIMARY KEY (index_num, index_pos) + PRIMARY KEY (block_num, block_pos) ); -CREATE TABLE bridge.bridge -( - index_num BIGINT NOT NULL REFERENCES bridge.index (index_num) ON DELETE CASCADE, - index_pos BIGINT NOT NULL, +CREATE TABLE bridge ( + block_num BIGINT NOT NULL REFERENCES block (block_num) ON DELETE CASCADE, + block_pos BIGINT NOT NULL, global_index DECIMAL(78, 0) NOT NULL, origin_network INTEGER NOT NULL, @@ -45,5 +42,5 @@ CREATE TABLE bridge.bridge metadata BLOB, is_message BOOLEAN, - PRIMARY KEY (index_num, index_pos) + PRIMARY KEY (block_num, block_pos) ); \ No newline at end of file diff --git a/bridgesync/migrations/0001_test.go b/bridgesync/migrations/0001_test.go new file mode 100644 index 00000000..ccf1640c --- /dev/null +++ b/bridgesync/migrations/0001_test.go @@ -0,0 +1,61 @@ +package migrations + +import ( + "context" + "path" + "testing" + + "github.com/0xPolygon/cdk/db" + "github.com/stretchr/testify/require" +) + +func Test001(t *testing.T) { + dbPath := path.Join(t.TempDir(), "tmp.db") + + err := RunMigrations(dbPath) + require.NoError(t, err) + db, err := db.NewSQLiteDB(dbPath) + require.NoError(t, err) + + ctx := context.Background() + tx, err := db.BeginTx(ctx, nil) + require.NoError(t, err) + + _, err = tx.Exec(` + INSERT INTO block (num) VALUES (1); + + INSERT INTO claim ( + block_num, + block_pos, + leaf_type, + origin_network, + origin_address, + destination_network, + destination_address, + amount, + metadata, + deposit_count + ) VALUES (1, 0, 0, 0, '0x0000', 0, '0x0000', 0, NULL, 0); + + INSERT INTO bridge ( + block_num, + block_pos, + global_index, + origin_network, + origin_address, + destination_address, + amount, + proof_local_exit_root, + proof_rollup_exit_root, + mainnet_exit_root, + rollup_exit_root, + global_exit_root, + destination_network, + metadata, + is_message + ) VALUES (1, 0, 0, 0, '0x0000', '0x0000', 0, '0x000,0x000', '0x000,0x000', '0x000', '0x000', '0x0', 0, NULL, FALSE); + `) + require.NoError(t, err) + err = tx.Commit() + require.NoError(t, err) +} diff --git a/bridgesync/migrations/migrations.go b/bridgesync/migrations/migrations.go index 0aa85608..38e9a41f 100644 --- a/bridgesync/migrations/migrations.go +++ b/bridgesync/migrations/migrations.go @@ -3,6 +3,7 @@ package migrations import ( "strings" + "github.com/0xPolygon/cdk/db" migrate "github.com/rubenv/sql-migrate" _ "embed" @@ -23,3 +24,7 @@ var Migrations = &migrate.MemoryMigrationSource{ }, }, } + +func RunMigrations(dbPath string) error { + return db.RunMigrations(dbPath, Migrations) +} diff --git a/bridgesync/processor.go b/bridgesync/processor.go index 8f7c0798..4cf42062 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -9,6 +9,7 @@ import ( "math/big" dbCommon "github.com/0xPolygon/cdk/common" + "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/log" "github.com/0xPolygon/cdk/sync" "github.com/0xPolygon/cdk/tree" @@ -71,6 +72,8 @@ func (b *Bridge) Hash() common.Hash { // Claim representation of a claim event type Claim struct { + BlockNum uint64 + BlockPos uint64 // From claim event GlobalIndex *big.Int OriginNetwork uint32 @@ -82,6 +85,7 @@ type Claim struct { ProofRollupExitRoot [tree.DefaultHeight]common.Hash MainnetExitRoot common.Hash RollupExitRoot common.Hash + GlobalExitRoot common.Hash DestinationNetwork uint32 Metadata []byte // Meta @@ -103,7 +107,7 @@ type processor struct { } func newProcessor(ctx context.Context, dbPath, dbPrefix string) (*processor, error) { - db, err := sql.Open("sqlite", dbPath) + db, err := db.NewSQLiteDB(dbPath) if err != nil { return nil, err } @@ -134,16 +138,21 @@ func newProcessor(ctx context.Context, dbPath, dbPrefix string) (*processor, err // GetClaimsAndBridges returns the claims and bridges occurred between fromBlock, toBlock both included. // If toBlock has not been porcessed yet, ErrBlockNotProcessed will be returned -func (p *processor) GetClaimsAndBridges( +func (p *processor) GetBridges( ctx context.Context, fromBlock, toBlock uint64, -) ([]Event, error) { - events := []Event{} +) ([]Bridge, error) { + return nil, nil +} - tx, err := p.db.BeginRo(ctx) +func (p *processor) GetClaims( + ctx context.Context, fromBlock, toBlock uint64, +) ([]Claim, error) { + tx, err := p.db.BeginTx(ctx, nil) if err != nil { return nil, err } defer tx.Rollback() + lpb, err := p.getLastProcessedBlockWithTx(tx) if err != nil { return nil, err @@ -151,34 +160,102 @@ func (p *processor) GetClaimsAndBridges( if lpb < toBlock { return nil, ErrBlockNotProcessed } - c, err := tx.Cursor(p.eventsTable) + + rows, err := tx.Query(` + SELECT + block_num, + block_pos, + global_index, + origin_network, + origin_address, + destination_address, + amount, + proof_local_exit_root, + proof_rollup_exit_root, + mainnet_exit_root, + rollup_exit_root, + global_exit_root, + destination_network, + is_message + metadata, + FROM bridge + WHERE block_num >= $1 AND block_num <= $2; + `) if err != nil { return nil, err } - defer c.Close() - - for k, v, err := c.Seek(dbCommon.Uint64ToBytes(fromBlock)); k != nil; k, v, err = c.Next() { + claims := []Claim{} + for rows.Next() { + b, err := scanClaim(rows) if err != nil { return nil, err } - if dbCommon.BytesToUint64(k) > toBlock { - break - } - blockEvents := []Event{} - err := json.Unmarshal(v, &blockEvents) - if err != nil { - return nil, err - } - events = append(events, blockEvents...) + claims = append(claims, b) } - return events, nil + return claims, nil +} + +func scanClaim(rows *sql.Rows) (Claim, error) { + var ( + block_num uint64 + block_pos uint64 + global_index *big.Int + origin_network uint32 + origin_address common.Address + destination_address common.Address + amount *big.Int + proof_local_exit_root common.Hash + proof_rollup_exit_root common.Hash + mainnet_exit_root common.Hash + rollup_exit_root common.Hash + global_exit_root common.Hash + destination_network uint32 + is_message bool + metadata []byte + ) + if err := rows.Scan( + &block_num, + &block_pos, + &global_index, + &origin_network, + &origin_address, + &destination_address, + &amount, + &proof_local_exit_root, + &proof_rollup_exit_root, + &mainnet_exit_root, + &rollup_exit_root, + &global_exit_root, + &destination_network, + &metadata, + &is_message, + ); err != nil { + return Claim{}, err + } + return Claim{ + BlockNum: block_num, + BlockPos: block_pos, + GlobalIndex: global_index, + OriginNetwork: origin_network, + OriginAddress: origin_address, + DestinationAddress: destination_address, + Amount: amount, + ProofLocalExitRoot: proof_local_exit_root, + ProofRollupExitRoot: proof_rollup_exit_root, + MainnetExitRoot: mainnet_exit_root, + GlobalExitRoot: rollup_exit_root, + RollupExitRoot: global_exit_root, + DestinationNetwork: destination_network, + Metadata: metadata, + IsMessage: is_message, + }, nil } // GetLastProcessedBlock returns the last processed block by the processor, including blocks // that don't have events func (p *processor) GetLastProcessedBlock(ctx context.Context) (uint64, error) { - tx, err := p.db.BeginRo(ctx) + tx, err := p.db.BeginTx(ctx, nil) if err != nil { return 0, err } @@ -186,58 +263,53 @@ func (p *processor) GetLastProcessedBlock(ctx context.Context) (uint64, error) { return p.getLastProcessedBlockWithTx(tx) } -func (p *processor) getLastProcessedBlockWithTx(tx kv.Tx) (uint64, error) { - if blockNumBytes, err := tx.GetOne(p.lastBlockTable, lastBlockKey); err != nil { - return 0, err - } else if blockNumBytes == nil { - return 0, nil - } else { - return dbCommon.BytesToUint64(blockNumBytes), nil - } +func (p *processor) getLastProcessedBlockWithTx(tx *sql.Tx) (uint64, error) { + var lastProcessedBlock uint64 + row := tx.QueryRow("SELECT num FROM BLOCK ORDER BY num DESC LIMIT 1;") + err := row.Scan(&lastProcessedBlock) + return lastProcessedBlock, err } // Reorg triggers a purge and reset process on the processor to leaf it on a state // as if the last block processed was firstReorgedBlock-1 func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { - tx, err := p.db.BeginRw(ctx) + tx, err := p.db.BeginTx(ctx, nil) if err != nil { return err } - defer tx.Rollback() - c, err := tx.Cursor(p.eventsTable) - if err != nil { - return err - } - defer c.Close() - firstKey := dbCommon.Uint64ToBytes(firstReorgedBlock) - firstDepositCountReorged := int64(-1) - for k, v, err := c.Seek(firstKey); k != nil; k, _, err = c.Next() { + defer func() { if err != nil { - tx.Rollback() - return err + if errRllbck := tx.Rollback(); errRllbck != nil { + log.Errorf("error while rolling back tx %v", errRllbck) + } } - if err := tx.Delete(p.eventsTable, k); err != nil { - tx.Rollback() + }() + + row := tx.QueryRow(` + SELECT deposit_count + FROM bridge + WHERE block_num >= $1 + ORDER BY (block_num, block_pos) ASC + LIMIT 1; + `) + var firstDepositCountReorged int + err = row.Scan(&firstDepositCountReorged) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + firstDepositCountReorged = -1 + } else { return err } - if firstDepositCountReorged == -1 { - events := []Event{} - if err := json.Unmarshal(v, &events); err != nil { - tx.Rollback() - return err - } - for _, event := range events { - if event.Bridge != nil { - firstDepositCountReorged = int64(event.Bridge.DepositCount) - break - } - } - } } - if err := p.updateLastProcessedBlock(tx, firstReorgedBlock-1); err != nil { - tx.Rollback() + + _, err = tx.Exec(`DELETE FROM block WHERE block >= $1;`, firstReorgedBlock) + if err != nil { + if errRllbck := tx.Rollback(); errRllbck != nil { + log.Errorf("error while rolling back tx %v", errRllbck) + } return err } + exitTreeRollback := func() {} if firstDepositCountReorged != -1 { if exitTreeRollback, err = p.exitTree.Reorg(tx, uint32(firstDepositCountReorged)); err != nil { diff --git a/db/migrations.go b/db/migrations.go index ddc83680..4fa1cca5 100644 --- a/db/migrations.go +++ b/db/migrations.go @@ -4,84 +4,24 @@ import ( "fmt" "github.com/0xPolygon/cdk/log" - "github.com/jackc/pgx/v4" - "github.com/jackc/pgx/v4/stdlib" migrate "github.com/rubenv/sql-migrate" + _ "modernc.org/sqlite" ) -// RunMigrationsUp runs migrate-up for the given config. -func RunMigrationsUp(cfg Config, name string) error { - log.Info("running migrations up") - return runMigrations(cfg, name, migrate.Up) -} - -// CheckMigrations runs migrate-up for the given config. -func CheckMigrations(cfg Config, name string) error { - return checkMigrations(cfg, name, migrate.Up) -} - -// RunMigrationsDown runs migrate-down for the given config. -func RunMigrationsDown(cfg Config, name string) error { - log.Info("running migrations down") - return runMigrations(cfg, name, migrate.Down) -} - -// runMigrations will execute pending migrations if needed to keep +// RunMigrations will execute pending migrations if needed to keep // the database updated with the latest changes in either direction, // up or down. -func runMigrations(cfg Config, migrations migrate.MigrationSource, direction migrate.MigrationDirection) error { - c, err := pgx.ParseConfig(fmt.Sprintf("sqlite://%s:%s@%s:%s/%s", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Name)) +func RunMigrations(dbPath string, migrations migrate.MigrationSource) error { + db, err := NewSQLiteDB(dbPath) if err != nil { - return err + return fmt.Errorf("error creating DB %w", err) } - db := stdlib.OpenDB(*c) - nMigrations, err := migrate.Exec(db, "sqlite", migrations, direction) + nMigrations, err := migrate.Exec(db, "sqlite3", migrations, migrate.Up) if err != nil { - return err + return fmt.Errorf("error executing migration %w", err) } log.Infof("successfully ran %d migrations", nMigrations) return nil } - -func checkMigrations(cfg Config, packrName string, direction migrate.MigrationDirection) error { - c, err := pgx.ParseConfig(fmt.Sprintf("postgres://%s:%s@%s:%s/%s", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Name)) - if err != nil { - return err - } - db := stdlib.OpenDB(*c) - - box, ok := packrMigrations[packrName] - if !ok { - return fmt.Errorf("packr box not found with name: %v", packrName) - } - - migrationSource := &migrate.PackrMigrationSource{Box: box} - migrations, err := migrationSource.FindMigrations() - if err != nil { - log.Errorf("error getting migrations from source: %v", err) - return err - } - - var expected int - for _, migration := range migrations { - if len(migration.Up) != 0 { - expected++ - } - } - - var actual int - query := `SELECT COUNT(1) FROM public.gorp_migrations` - err = db.QueryRow(query).Scan(&actual) - if err != nil { - log.Error("error getting migrations count: ", err) - return err - } - if expected == actual { - log.Infof("Found %d migrations as expected", actual) - } else { - return fmt.Errorf("error the component needs to run %d migrations before starting. DB only contains %d migrations", expected, actual) - } - return nil -} diff --git a/db/sqlite.go b/db/sqlite.go index 75d28d0d..01e1361c 100644 --- a/db/sqlite.go +++ b/db/sqlite.go @@ -1,27 +1,12 @@ package db import ( - "context" - "fmt" + "database/sql" - "github.com/0xPolygon/cdk/log" - "github.com/jackc/pgx/v4/pgxpool" + _ "modernc.org/sqlite" ) // NewSQLiteDB creates a new SQLite DB -func NewSQLiteDB(cfg Config) (*pgxpool.Pool, error) { - config, err := pgxpool.ParseConfig(fmt.Sprintf("postgres://%s:%s@%s:%s/%s?pool_max_conns=%d", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Name, cfg.MaxConns)) - if err != nil { - log.Errorf("Unable to parse DB config: %v\n", err) - return nil, err - } - if cfg.EnableLog { - config.ConnConfig.Logger = logger{} - } - conn, err := pgxpool.ConnectConfig(context.Background(), config) - if err != nil { - log.Errorf("Unable to connect to database: %v\n", err) - return nil, err - } - return conn, nil +func NewSQLiteDB(dbPath string) (*sql.DB, error) { + return sql.Open("sqlite", dbPath) } diff --git a/go.mod b/go.mod index 5f1e0744..b20bc050 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/iden3/go-iden3-crypto v0.0.16 github.com/invopop/jsonschema v0.12.0 github.com/jackc/pgconn v1.14.3 + github.com/jackc/pgx v3.6.2+incompatible github.com/jackc/pgx/v4 v4.18.3 github.com/ledgerwatch/erigon-lib v1.0.0 github.com/mitchellh/mapstructure v1.5.0 @@ -30,6 +31,7 @@ require ( golang.org/x/sync v0.7.0 google.golang.org/grpc v1.64.0 google.golang.org/protobuf v1.34.2 + modernc.org/sqlite v1.32.0 ) require ( @@ -87,6 +89,7 @@ require ( github.com/holiman/uint256 v1.2.4 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.3.3 // indirect @@ -157,7 +160,6 @@ require ( modernc.org/libc v1.60.0 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.8.0 // indirect - modernc.org/sqlite v1.32.0 // indirect modernc.org/strutil v1.2.0 // indirect modernc.org/token v1.1.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index e7b35224..e9a8d962 100644 --- a/go.sum +++ b/go.sum @@ -166,6 +166,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -176,7 +178,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDa github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.1-0.20180906183839-65a6292f0157 h1:uyodBE3xDz0ynKs1tLBU26wOQoEkAqqiY18DbZ+FZrA= @@ -201,6 +202,8 @@ github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9 github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= @@ -235,6 +238,8 @@ github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrU github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o= +github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= @@ -481,6 +486,8 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -533,8 +540,6 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -563,6 +568,8 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -606,6 +613,14 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= +modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v4 v4.21.0 h1:kKPI3dF7RIag8YcToh5ZwDcVMIv6VGa0ED5cvh0LMW4= +modernc.org/ccgo/v4 v4.21.0/go.mod h1:h6kt6H/A2+ew/3MW/p6KEoQmrq/i3pr0J/SiwiaF/g0= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.5.0 h1:bJ9ChznK1L1mUtAQtxi0wi5AtAs5jQuw4PrPHO5pb6M= +modernc.org/gc/v2 v2.5.0/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a h1:CfbpOLEo2IwNzJdMvE8aiRbPMxoTpgAJeyePh0SmO8M= modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= modernc.org/libc v1.60.0 h1:XeRF1gXky7JE5E8IErtYAdKj+ykZPdYUsgJNQ8RFWIA= @@ -614,6 +629,10 @@ modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= +modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s= modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= diff --git a/tree/tree.go b/tree/tree.go index 77c0e452..5b80278d 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -168,6 +168,10 @@ func (t *Tree) getSiblings(tx kv.Tx, index uint32, root common.Hash) ( return } +func (t *Tree) BeginRw(ctx context.Context) (kv.RwTx, error) { + return t.db.BeginRw(ctx) +} + // GetProof returns the merkle proof for a given index and root. func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) ([DefaultHeight]common.Hash, error) { tx, err := t.db.BeginRw(ctx) From 78a2aca9ce3a1d0b18305bcc8c8a13b4e164c5be Mon Sep 17 00:00:00 2001 From: Arnau Date: Tue, 3 Sep 2024 19:59:00 +0200 Subject: [PATCH 10/31] tree migrated to SQLite --- .../{0001.sql => bridgesync0001.sql} | 0 .../{0001_test.go => bridgesync0001_test.go} | 0 bridgesync/migrations/migrations.go | 2 +- bridgesync/processor.go | 95 ++------- db/sqlite.go | 3 + go.mod | 1 + go.sum | 3 + tree/appendonlytree.go | 199 ++++-------------- tree/migrations/migrations.go | 30 +++ tree/migrations/tree0001.sql | 17 ++ tree/migrations/tree001_test.go | 1 + tree/tree.go | 191 ++++++----------- tree/tree_test.go | 86 +++----- tree/updatabletree.go | 124 ++--------- 14 files changed, 236 insertions(+), 516 deletions(-) rename bridgesync/migrations/{0001.sql => bridgesync0001.sql} (100%) rename bridgesync/migrations/{0001_test.go => bridgesync0001_test.go} (100%) create mode 100644 tree/migrations/migrations.go create mode 100644 tree/migrations/tree0001.sql create mode 100644 tree/migrations/tree001_test.go diff --git a/bridgesync/migrations/0001.sql b/bridgesync/migrations/bridgesync0001.sql similarity index 100% rename from bridgesync/migrations/0001.sql rename to bridgesync/migrations/bridgesync0001.sql diff --git a/bridgesync/migrations/0001_test.go b/bridgesync/migrations/bridgesync0001_test.go similarity index 100% rename from bridgesync/migrations/0001_test.go rename to bridgesync/migrations/bridgesync0001_test.go diff --git a/bridgesync/migrations/migrations.go b/bridgesync/migrations/migrations.go index 38e9a41f..e4a5d4ff 100644 --- a/bridgesync/migrations/migrations.go +++ b/bridgesync/migrations/migrations.go @@ -11,7 +11,7 @@ import ( const upDownSeparator = "-- +migrate Up" -//go:embed 0001.sql +//go:embed bridgesync0001.sql var mig001 string var mig001splitted = strings.Split(mig001, upDownSeparator) diff --git a/bridgesync/processor.go b/bridgesync/processor.go index 4cf42062..45a43052 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -17,6 +17,7 @@ import ( "github.com/iden3/go-iden3-crypto/keccak256" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/mdbx" + "github.com/russross/meddler" _ "modernc.org/sqlite" ) @@ -178,78 +179,15 @@ func (p *processor) GetClaims( destination_network, is_message metadata, - FROM bridge + FROM claim WHERE block_num >= $1 AND block_num <= $2; `) if err != nil { return nil, err } claims := []Claim{} - for rows.Next() { - b, err := scanClaim(rows) - if err != nil { - return nil, err - } - claims = append(claims, b) - } - - return claims, nil -} - -func scanClaim(rows *sql.Rows) (Claim, error) { - var ( - block_num uint64 - block_pos uint64 - global_index *big.Int - origin_network uint32 - origin_address common.Address - destination_address common.Address - amount *big.Int - proof_local_exit_root common.Hash - proof_rollup_exit_root common.Hash - mainnet_exit_root common.Hash - rollup_exit_root common.Hash - global_exit_root common.Hash - destination_network uint32 - is_message bool - metadata []byte - ) - if err := rows.Scan( - &block_num, - &block_pos, - &global_index, - &origin_network, - &origin_address, - &destination_address, - &amount, - &proof_local_exit_root, - &proof_rollup_exit_root, - &mainnet_exit_root, - &rollup_exit_root, - &global_exit_root, - &destination_network, - &metadata, - &is_message, - ); err != nil { - return Claim{}, err - } - return Claim{ - BlockNum: block_num, - BlockPos: block_pos, - GlobalIndex: global_index, - OriginNetwork: origin_network, - OriginAddress: origin_address, - DestinationAddress: destination_address, - Amount: amount, - ProofLocalExitRoot: proof_local_exit_root, - ProofRollupExitRoot: proof_rollup_exit_root, - MainnetExitRoot: mainnet_exit_root, - GlobalExitRoot: rollup_exit_root, - RollupExitRoot: global_exit_root, - DestinationNetwork: destination_network, - Metadata: metadata, - IsMessage: is_message, - }, nil + err = meddler.ScanAll(rows, claims) + return claims, err } // GetLastProcessedBlock returns the last processed block by the processor, including blocks @@ -311,8 +249,12 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { } exitTreeRollback := func() {} + treeTx, err := p.exitTree.BeginRw(ctx) + if err != nil { + return err + } if firstDepositCountReorged != -1 { - if exitTreeRollback, err = p.exitTree.Reorg(tx, uint32(firstDepositCountReorged)); err != nil { + if exitTreeRollback, err = p.exitTree.Reorg(treeTx, uint32(firstDepositCountReorged)); err != nil { tx.Rollback() exitTreeRollback() return err @@ -328,10 +270,19 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { // ProcessBlock process the events of the block to build the exit tree // and updates the last processed block (can be called without events for that purpose) func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { - tx, err := p.db.BeginRw(ctx) + tx, err := p.db.BeginTx(ctx, nil) if err != nil { return err } + var exitTreeRollback func() + defer func() { + if err != nil { + if errRllbck := tx.Rollback(); errRllbck != nil { + log.Errorf("error while rolling back tx %v", errRllbck) + } + } + }() + leaves := []tree.Leaf{} if len(block.Events) > 0 { events := []Event{} @@ -345,6 +296,9 @@ func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { }) } } + if _, err := tx.Exec(`INSERT INTO block (num) VALUES ($1)`, block.Num); err != nil { + return err + } value, err := json.Marshal(events) if err != nil { tx.Rollback() @@ -356,11 +310,6 @@ func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { } } - if err := p.updateLastProcessedBlock(tx, block.Num); err != nil { - tx.Rollback() - return err - } - exitTreeRollback, err := p.exitTree.AddLeaves(tx, leaves) if err != nil { tx.Rollback() diff --git a/db/sqlite.go b/db/sqlite.go index 01e1361c..1c0357af 100644 --- a/db/sqlite.go +++ b/db/sqlite.go @@ -3,10 +3,13 @@ package db import ( "database/sql" + "github.com/russross/meddler" _ "modernc.org/sqlite" ) // NewSQLiteDB creates a new SQLite DB func NewSQLiteDB(dbPath string) (*sql.DB, error) { + meddler.Default = meddler.SQLite + meddler.Mapper = meddler.SnakeCase return sql.Open("sqlite", dbPath) } diff --git a/go.mod b/go.mod index b20bc050..f85b4f26 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/ledgerwatch/erigon-lib v1.0.0 github.com/mitchellh/mapstructure v1.5.0 github.com/rubenv/sql-migrate v1.6.1 + github.com/russross/meddler v1.0.1 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 github.com/urfave/cli/v2 v2.27.2 diff --git a/go.sum b/go.sum index e9a8d962..652a5a5d 100644 --- a/go.sum +++ b/go.sum @@ -306,6 +306,7 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI= github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/miguelmota/go-solidity-sha3 v0.1.1 h1:3Y08sKZDtudtE5kbTBPC9RYJznoSYyWI9VD6mghU0CA= @@ -377,6 +378,8 @@ github.com/rubenv/sql-migrate v1.6.1 h1:bo6/sjsan9HaXAsNxYP/jCEDUGibHp8JmOBw7NTG github.com/rubenv/sql-migrate v1.6.1/go.mod h1:tPzespupJS0jacLfhbwto/UjSX+8h2FdWB7ar+QlHa0= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/meddler v1.0.1 h1:JLR7Z4M4iGm1nr7DIURBq18UW8cTrm+qArUFgOhELo8= +github.com/russross/meddler v1.0.1/go.mod h1:GzGDChbFHuzxlFwt8gnJMRRNyFSQDSudmy2kHh7GYnQ= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= diff --git a/tree/appendonlytree.go b/tree/appendonlytree.go index 5b714bfb..0dac5051 100644 --- a/tree/appendonlytree.go +++ b/tree/appendonlytree.go @@ -1,12 +1,10 @@ package tree import ( - "context" + "database/sql" "fmt" - dbCommon "github.com/0xPolygon/cdk/common" "github.com/ethereum/go-ethereum/common" - "github.com/ledgerwatch/erigon-lib/kv" ) // AppendOnlyTree is a tree where leaves are added sequentially (by index) @@ -17,47 +15,23 @@ type AppendOnlyTree struct { } // NewAppendOnlyTree creates a AppendOnlyTree -func NewAppendOnlyTree(ctx context.Context, db kv.RwDB, dbPrefix string) (*AppendOnlyTree, error) { - t := newTree(db, dbPrefix) - at := &AppendOnlyTree{Tree: t} - if err := at.initLastLeftCacheAndLastDepositCount(ctx); err != nil { - return nil, err - } - return at, nil -} - -// AddLeaves adds a list leaves into the tree. The indexes of the leaves must be consecutive, -// starting by the index of the last leaf added +1 -// It returns a function that must be called to rollback the changes done by this interaction -func (t *AppendOnlyTree) AddLeaves(tx kv.RwTx, leaves []Leaf) (func(), error) { - // Sanity check - if len(leaves) == 0 { - return func() {}, nil - } - - backupIndx := t.lastIndex - backupCache := [DefaultHeight]common.Hash{} - copy(backupCache[:], t.lastLeftCache[:]) - rollback := func() { - t.lastIndex = backupIndx - t.lastLeftCache = backupCache - } - - for _, leaf := range leaves { - if err := t.addLeaf(tx, leaf); err != nil { - return rollback, err - } - } - - return rollback, nil +func NewAppendOnlyTree(db *sql.DB) *AppendOnlyTree { + t := newTree(db) + return &AppendOnlyTree{Tree: t} } -func (t *AppendOnlyTree) addLeaf(tx kv.RwTx, leaf Leaf) error { +func (t *AppendOnlyTree) AddLeaf(tx *sql.Tx, blockNum, blockPosition uint64, leaf Leaf) error { if int64(leaf.Index) != t.lastIndex+1 { - return fmt.Errorf( - "mismatched index. Expected: %d, actual: %d", - t.lastIndex+1, leaf.Index, - ) + // rebuild cache + if err := t.initCache(tx); err != nil { + return err + } + if int64(leaf.Index) != t.lastIndex+1 { + return fmt.Errorf( + "mismatched index. Expected: %d, actual: %d", + t.lastIndex+1, leaf.Index, + ) + } } // Calculate new tree nodes currentChildHash := leaf.Hash @@ -66,31 +40,27 @@ func (t *AppendOnlyTree) addLeaf(tx kv.RwTx, leaf Leaf) error { var parent treeNode if leaf.Index&(1< 0 { // Add child to the right - parent = treeNode{ - left: t.lastLeftCache[h], - right: currentChildHash, - } + parent = newTreeNode(t.lastLeftCache[h], currentChildHash) } else { // Add child to the left - parent = treeNode{ - left: currentChildHash, - right: t.zeroHashes[h], - } + parent = newTreeNode(currentChildHash, t.zeroHashes[h]) // Update cache - // TODO: review this part of the logic, skipping ?optimizaton? - // from OG implementation t.lastLeftCache[h] = currentChildHash } - currentChildHash = parent.hash() + currentChildHash = parent.Hash newNodes = append(newNodes, parent) } // store root - t.storeRoot(tx, uint64(leaf.Index), currentChildHash) - root := currentChildHash - if err := tx.Put(t.rootTable, dbCommon.Uint64ToBytes(uint64(leaf.Index)), root[:]); err != nil { + if err := t.storeRoot(tx, Root{ + Hash: currentChildHash, + Index: leaf.Index, + BlockNum: blockNum, + BlockPosition: blockPosition, + }); err != nil { return err } + // store nodes if err := t.storeNodes(tx, newNodes); err != nil { return err @@ -99,87 +69,37 @@ func (t *AppendOnlyTree) addLeaf(tx kv.RwTx, leaf Leaf) error { return nil } -// GetRootByIndex returns the root of the tree as it was right after adding the leaf with index -func (t *AppendOnlyTree) GetRootByIndex(tx kv.Tx, index uint32) (common.Hash, error) { - return t.getRootByIndex(tx, uint64(index)) -} - -func (t *AppendOnlyTree) GetIndexByRoot(ctx context.Context, root common.Hash) (uint32, error) { - tx, err := t.db.BeginRo(ctx) - if err != nil { - return 0, err - } - defer tx.Rollback() - index, err := t.getIndexByRoot(tx, root) - return uint32(index), err -} - -// GetLastIndexAndRoot returns the last index and root added to the tree -func (t *AppendOnlyTree) GetLastIndexAndRoot(ctx context.Context) (uint32, common.Hash, error) { - tx, err := t.db.BeginRo(ctx) - if err != nil { - return 0, common.Hash{}, err - } - defer tx.Rollback() - i, root, err := t.getLastIndexAndRootWithTx(tx) - if err != nil { - return 0, common.Hash{}, err - } - if i == -1 { - return 0, common.Hash{}, ErrNotFound - } - return uint32(i), root, nil -} - -func (t *AppendOnlyTree) initLastLeftCacheAndLastDepositCount(ctx context.Context) error { - tx, err := t.db.BeginRw(ctx) - if err != nil { - return err - } - defer tx.Rollback() - - root, err := t.initLastIndex(tx) +func (t *AppendOnlyTree) initCache(tx *sql.Tx) error { + siblings := [DefaultHeight]common.Hash{} + lastRoot, err := t.getLastRootWithTx(tx) if err != nil { + if err == ErrNotFound { + t.lastIndex = -1 + t.lastLeftCache = siblings + return nil + } return err } - return t.initLastLeftCache(tx, t.lastIndex, root) -} - -func (t *AppendOnlyTree) initLastIndex(tx kv.Tx) (common.Hash, error) { - lastIndex, root, err := t.getLastIndexAndRootWithTx(tx) - if err != nil { - return common.Hash{}, err - } - t.lastIndex = lastIndex - return root, nil -} - -func (t *AppendOnlyTree) initLastLeftCache(tx kv.Tx, lastIndex int64, lastRoot common.Hash) error { - siblings := [DefaultHeight]common.Hash{} - if lastIndex == -1 { - t.lastLeftCache = siblings - return nil - } - index := lastIndex - - currentNodeHash := lastRoot + t.lastIndex = int64(lastRoot.Index) + currentNodeHash := lastRoot.Hash + index := t.lastIndex // It starts in height-1 because 0 is the level of the leafs for h := int(DefaultHeight - 1); h >= 0; h-- { currentNode, err := t.getRHTNode(tx, currentNodeHash) if err != nil { return fmt.Errorf( "error getting node %s from the RHT at height %d with root %s: %v", - currentNodeHash.Hex(), h, lastRoot.Hex(), err, + currentNodeHash.Hex(), h, lastRoot.Hash.Hex(), err, ) } if currentNode == nil { return ErrNotFound } - siblings[h] = currentNode.left + siblings[h] = currentNode.Left if index&(1< 0 { - currentNodeHash = currentNode.right + currentNodeHash = currentNode.Right } else { - currentNodeHash = currentNode.left + currentNodeHash = currentNode.Left } } @@ -191,42 +111,3 @@ func (t *AppendOnlyTree) initLastLeftCache(tx kv.Tx, lastIndex int64, lastRoot c t.lastLeftCache = siblings return nil } - -// Reorg deletes all the data relevant from firstReorgedIndex (includded) and onwards -// and prepares the tree tfor being used as it was at firstReorgedIndex-1 -// It returns a function that must be called to rollback the changes done by this interaction -func (t *AppendOnlyTree) Reorg(tx kv.RwTx, firstReorgedIndex uint32) (func(), error) { - if t.lastIndex == -1 { - return func() {}, nil - } - // Clean root table - for i := firstReorgedIndex; i <= uint32(t.lastIndex); i++ { - if err := tx.Delete(t.rootTable, dbCommon.Uint64ToBytes(uint64(i))); err != nil { - return func() {}, err - } - } - - // Reset - root := common.Hash{} - if firstReorgedIndex > 0 { - rootBytes, err := tx.GetOne(t.rootTable, dbCommon.Uint64ToBytes(uint64(firstReorgedIndex)-1)) - if err != nil { - return func() {}, err - } - if rootBytes == nil { - return func() {}, ErrNotFound - } - root = common.Hash(rootBytes) - } - err := t.initLastLeftCache(tx, int64(firstReorgedIndex)-1, root) - if err != nil { - return func() {}, err - } - - // Note: not cleaning RHT, not worth it - backupLastIndex := t.lastIndex - t.lastIndex = int64(firstReorgedIndex) - 1 - return func() { - t.lastIndex = backupLastIndex - }, nil -} diff --git a/tree/migrations/migrations.go b/tree/migrations/migrations.go new file mode 100644 index 00000000..b1f1629f --- /dev/null +++ b/tree/migrations/migrations.go @@ -0,0 +1,30 @@ +package migrations + +import ( + "strings" + + "github.com/0xPolygon/cdk/db" + migrate "github.com/rubenv/sql-migrate" + + _ "embed" +) + +const upDownSeparator = "-- +migrate Up" + +//go:embed tree0001.sql +var mig001 string +var mig001splitted = strings.Split(mig001, upDownSeparator) + +var Migrations = &migrate.MemoryMigrationSource{ + Migrations: []*migrate.Migration{ + { + Id: "001", + Up: []string{mig001splitted[1]}, + Down: []string{mig001splitted[0]}, + }, + }, +} + +func RunMigrations(dbPath string) error { + return db.RunMigrations(dbPath, Migrations) +} diff --git a/tree/migrations/tree0001.sql b/tree/migrations/tree0001.sql new file mode 100644 index 00000000..bc2e6751 --- /dev/null +++ b/tree/migrations/tree0001.sql @@ -0,0 +1,17 @@ +-- +migrate Down +DROP TABLE IF EXISTS root; +DROP TABLE IF EXISTS rht; + +-- +migrate Up +CREATE TABLE root ( + hash VARCHAR PRIMARY KEY, + position INTEGER NOT NULL UNIQUE, + block_num BIGINT NOT NULL, + block_position BIGINT NOT NULL +); + +CREATE TABLE rht ( + hash VARCHAR PRIMARY KEY, + left VARCHAR NOT NULL, + right VARCHAR NOT NULL +); diff --git a/tree/migrations/tree001_test.go b/tree/migrations/tree001_test.go new file mode 100644 index 00000000..a6ea3eef --- /dev/null +++ b/tree/migrations/tree001_test.go @@ -0,0 +1 @@ +package migrations diff --git a/tree/tree.go b/tree/tree.go index 5b80278d..558523d9 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -2,25 +2,21 @@ package tree import ( "context" + "database/sql" "errors" "fmt" - "math" - dbCommon "github.com/0xPolygon/cdk/common" "github.com/ethereum/go-ethereum/common" - "github.com/ledgerwatch/erigon-lib/kv" + "github.com/russross/meddler" "golang.org/x/crypto/sha3" ) const ( - DefaultHeight uint8 = 32 - rootTableSufix = "-root" - rhtTableSufix = "-rht" - indexTableSufix = "-index" + DefaultHeight uint8 = 32 ) var ( - EmptyProof = [32]common.Hash{} + EmptyProof = Proof{} ErrNotFound = errors.New("not found") ) @@ -29,59 +25,54 @@ type Leaf struct { Hash common.Hash } +type Proof [DefaultHeight]common.Hash + +type Root struct { + Hash common.Hash `meddler:"hash"` + Index uint32 `meddler:"position"` + BlockNum uint64 `meddler:"block_num"` + BlockPosition uint64 `meddler:"block_position"` +} + type Tree struct { - db kv.RwDB - rhtTable string - rootTable string - indexTable string + db *sql.DB zeroHashes []common.Hash } type treeNode struct { - left common.Hash - right common.Hash + Hash common.Hash `meddler:"hash"` + Left common.Hash `meddler:"left"` + Right common.Hash `meddler:"right"` } -func (n *treeNode) hash() common.Hash { +func newTreeNode(left, right common.Hash) treeNode { var hash common.Hash hasher := sha3.NewLegacyKeccak256() - hasher.Write(n.left[:]) - hasher.Write(n.right[:]) + hasher.Write(left[:]) + hasher.Write(right[:]) copy(hash[:], hasher.Sum(nil)) - return hash + return treeNode{ + Hash: hash, + Left: left, + Right: right, + } } func (n *treeNode) MarshalBinary() ([]byte, error) { - return append(n.left[:], n.right[:]...), nil + return append(n.Left[:], n.Right[:]...), nil } func (n *treeNode) UnmarshalBinary(data []byte) error { if len(data) != 64 { return fmt.Errorf("expected len %d, actual len %d", 64, len(data)) } - n.left = common.Hash(data[:32]) - n.right = common.Hash(data[32:]) + n.Left = common.Hash(data[:32]) + n.Right = common.Hash(data[32:]) return nil } -// AddTables add the needed tables for the tree to work in a tableCfg -func AddTables(tableCfg map[string]kv.TableCfgItem, dbPrefix string) { - rootTable := dbPrefix + rootTableSufix - rhtTable := dbPrefix + rhtTableSufix - indexTable := dbPrefix + indexTableSufix - tableCfg[rootTable] = kv.TableCfgItem{} - tableCfg[rhtTable] = kv.TableCfgItem{} - tableCfg[indexTable] = kv.TableCfgItem{} -} - -func newTree(db kv.RwDB, dbPrefix string) *Tree { - rootTable := dbPrefix + rootTableSufix - rhtTable := dbPrefix + rhtTableSufix - indexTable := dbPrefix + indexTableSufix +func newTree(db *sql.DB) *Tree { t := &Tree{ - rhtTable: rhtTable, - rootTable: rootTable, - indexTable: indexTable, db: db, zeroHashes: generateZeroHashes(DefaultHeight), } @@ -89,29 +80,7 @@ func newTree(db kv.RwDB, dbPrefix string) *Tree { return t } -func (t *Tree) getRootByIndex(tx kv.Tx, index uint64) (common.Hash, error) { - rootBytes, err := tx.GetOne(t.rootTable, dbCommon.Uint64ToBytes(index)) - if err != nil { - return common.Hash{}, err - } - if rootBytes == nil { - return common.Hash{}, ErrNotFound - } - return common.BytesToHash(rootBytes), nil -} - -func (t *Tree) getIndexByRoot(tx kv.Tx, root common.Hash) (uint64, error) { - indexBytes, err := tx.GetOne(t.indexTable, root[:]) - if err != nil { - return 0, err - } - if indexBytes == nil { - return 0, ErrNotFound - } - return dbCommon.BytesToUint64(indexBytes), nil -} - -func (t *Tree) getSiblings(tx kv.Tx, index uint32, root common.Hash) ( +func (t *Tree) getSiblings(tx *sql.Tx, index uint32, root common.Hash) ( siblings [32]common.Hash, hasUsedZeroHashes bool, err error, @@ -157,24 +126,20 @@ func (t *Tree) getSiblings(tx kv.Tx, index uint32, root common.Hash) ( * Now, let's do AND operation => 100&100=100 which is higher than 0 so we need the left sibling (O5) */ if index&(1< 0 { - siblings[h] = currentNode.left - currentNodeHash = currentNode.right + siblings[h] = currentNode.Left + currentNodeHash = currentNode.Right } else { - siblings[h] = currentNode.right - currentNodeHash = currentNode.left + siblings[h] = currentNode.Right + currentNodeHash = currentNode.Left } } return } -func (t *Tree) BeginRw(ctx context.Context) (kv.RwTx, error) { - return t.db.BeginRw(ctx) -} - // GetProof returns the merkle proof for a given index and root. func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) ([DefaultHeight]common.Hash, error) { - tx, err := t.db.BeginRw(ctx) + tx, err := t.db.BeginTx(ctx, nil) if err != nil { return [DefaultHeight]common.Hash{}, err } @@ -189,16 +154,15 @@ func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) ([D return siblings, nil } -func (t *Tree) getRHTNode(tx kv.Tx, nodeHash common.Hash) (*treeNode, error) { - nodeBytes, err := tx.GetOne(t.rhtTable, nodeHash[:]) +func (t *Tree) getRHTNode(tx *sql.Tx, nodeHash common.Hash) (*treeNode, error) { + node := &treeNode{} + err := meddler.QueryRow(tx, node, `select * from rht where hash = $1`, nodeHash) if err != nil { - return nil, err - } - if nodeBytes == nil { - return nil, ErrNotFound + if errors.Is(err, sql.ErrNoRows) { + return node, ErrNotFound + } + return node, err } - node := &treeNode{} - err = node.UnmarshalBinary(nodeBytes) return node, err } @@ -219,69 +183,43 @@ func generateZeroHashes(height uint8) []common.Hash { return zeroHashes } -func (t *Tree) storeNodes(tx kv.RwTx, nodes []treeNode) error { +func (t *Tree) storeNodes(tx *sql.Tx, nodes []treeNode) error { for _, node := range nodes { - value, err := node.MarshalBinary() - if err != nil { - return err - } - if err := tx.Put(t.rhtTable, node.hash().Bytes(), value); err != nil { + if err := meddler.Insert(tx, "rht", &node); err != nil { return err } } return nil } -func (t *Tree) storeRoot(tx kv.RwTx, rootIndex uint64, root common.Hash) error { - if err := tx.Put(t.rootTable, dbCommon.Uint64ToBytes(rootIndex), root[:]); err != nil { - return err - } - return tx.Put(t.indexTable, root[:], dbCommon.Uint64ToBytes(rootIndex)) +func (t *Tree) storeRoot(tx *sql.Tx, root Root) error { + return meddler.Insert(tx, "root", &root) } // GetLastRoot returns the last processed root -func (t *Tree) GetLastRoot(ctx context.Context) (common.Hash, error) { - tx, err := t.db.BeginRo(ctx) +func (t *Tree) GetLastRoot(ctx context.Context) (Root, error) { + tx, err := t.db.BeginTx(ctx, nil) if err != nil { - return common.Hash{}, err + return Root{}, err } defer tx.Rollback() - - i, root, err := t.getLastIndexAndRootWithTx(tx) - if err != nil { - return common.Hash{}, err - } - if i == -1 { - return common.Hash{}, ErrNotFound - } - return root, nil + return t.getLastRootWithTx(tx) } -// getLastIndexAndRootWithTx return the index and the root associated to the last leaf inserted. -// If index == -1, it means no leaf added yet -func (t *Tree) getLastIndexAndRootWithTx(tx kv.Tx) (int64, common.Hash, error) { - iter, err := tx.RangeDescend( - t.rootTable, - dbCommon.Uint64ToBytes(math.MaxUint64), - dbCommon.Uint64ToBytes(0), - 1, - ) - if err != nil { - return 0, common.Hash{}, err - } - - lastIndexBytes, rootBytes, err := iter.Next() +func (t *Tree) getLastRootWithTx(tx *sql.Tx) (Root, error) { + var root Root + err := meddler.QueryRow(tx, &root, `SELECT * FROM root ORDER BY block_num DESC, block_position DESC LIMIT 1;`) if err != nil { - return 0, common.Hash{}, err - } - if lastIndexBytes == nil { - return -1, common.Hash{}, nil + if errors.Is(err, sql.ErrNoRows) { + return root, ErrNotFound + } + return root, err } - return int64(dbCommon.BytesToUint64(lastIndexBytes)), common.Hash(rootBytes), nil + return root, nil } func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (common.Hash, error) { - tx, err := t.db.BeginRo(ctx) + tx, err := t.db.BeginTx(ctx, nil) if err != nil { return common.Hash{}, err } @@ -294,11 +232,18 @@ func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (com return common.Hash{}, err } if index&(1< 0 { - currentNodeHash = currentNode.right + currentNodeHash = currentNode.Right } else { - currentNodeHash = currentNode.left + currentNodeHash = currentNode.Left } } return currentNodeHash, nil } + +// Reorg deletes all the data relevant from firstReorgedBlock (includded) and onwards +func (t *AppendOnlyTree) Reorg(tx *sql.Tx, firstReorgedBlock uint32) error { + _, err := tx.Exec(`DELETE FROM root WHERE block_num >= $1`, firstReorgedBlock) + return err + // NOTE: rht is not cleaned, this could be done in the future as optimization +} diff --git a/tree/tree_test.go b/tree/tree_test.go index 3c27854f..1e7fb249 100644 --- a/tree/tree_test.go +++ b/tree/tree_test.go @@ -5,12 +5,14 @@ import ( "encoding/json" "fmt" "os" + "path" "testing" + "github.com/0xPolygon/cdk/db" + "github.com/0xPolygon/cdk/log" + "github.com/0xPolygon/cdk/tree/migrations" "github.com/0xPolygon/cdk/tree/testvectors" "github.com/ethereum/go-ethereum/common" - "github.com/ledgerwatch/erigon-lib/kv" - "github.com/ledgerwatch/erigon-lib/kv/mdbx" "github.com/stretchr/testify/require" ) @@ -25,59 +27,44 @@ func TestMTAddLeaf(t *testing.T) { for ti, testVector := range mtTestVectors { t.Run(fmt.Sprintf("Test vector %d", ti), func(t *testing.T) { - path := t.TempDir() - dbPrefix := "foo" - tableCfgFunc := func(defaultBuckets kv.TableCfg) kv.TableCfg { - cfg := kv.TableCfg{} - AddTables(cfg, dbPrefix) - return cfg - } - db, err := mdbx.NewMDBX(nil). - Path(path). - WithTableCfg(tableCfgFunc). - Open() + dbPath := path.Join(t.TempDir(), "tmp.db") + log.Debug("DB created at: ", dbPath) + err := migrations.RunMigrations(dbPath) require.NoError(t, err) - tree, err := NewAppendOnlyTree(context.Background(), db, dbPrefix) + db, err := db.NewSQLiteDB(dbPath) require.NoError(t, err) + tree := NewAppendOnlyTree(db) // Add exisiting leaves - leaves := []Leaf{} + tx, err := db.BeginTx(ctx, nil) + require.NoError(t, err) for i, leaf := range testVector.ExistingLeaves { - leaves = append(leaves, Leaf{ + err = tree.AddLeaf(tx, uint64(i), 0, Leaf{ Index: uint32(i), Hash: common.HexToHash(leaf), }) + require.NoError(t, err) } - tx, err := db.BeginRw(ctx) - require.NoError(t, err) - _, err = tree.AddLeaves(tx, leaves) - require.NoError(t, err) require.NoError(t, tx.Commit()) if len(testVector.ExistingLeaves) > 0 { - txRo, err := tree.db.BeginRo(ctx) - require.NoError(t, err) - _, actualRoot, err := tree.getLastIndexAndRootWithTx(txRo) - txRo.Rollback() + root, err := tree.GetLastRoot(ctx) require.NoError(t, err) - require.Equal(t, common.HexToHash(testVector.CurrentRoot), actualRoot) + require.Equal(t, common.HexToHash(testVector.CurrentRoot), root.Hash) } // Add new bridge - tx, err = db.BeginRw(ctx) + tx, err = db.BeginTx(ctx, nil) require.NoError(t, err) - _, err = tree.AddLeaves(tx, []Leaf{{ + err = tree.AddLeaf(tx, uint64(len(testVector.ExistingLeaves)), 0, Leaf{ Index: uint32(len(testVector.ExistingLeaves)), Hash: common.HexToHash(testVector.NewLeaf.CurrentHash), - }}) + }) require.NoError(t, err) require.NoError(t, tx.Commit()) - txRo, err := tree.db.BeginRo(ctx) - require.NoError(t, err) - _, actualRoot, err := tree.getLastIndexAndRootWithTx(txRo) - txRo.Rollback() + root, err := tree.GetLastRoot(ctx) require.NoError(t, err) - require.Equal(t, common.HexToHash(testVector.NewRoot), actualRoot) + require.Equal(t, common.HexToHash(testVector.NewRoot), root.Hash) }) } } @@ -93,41 +80,28 @@ func TestMTGetProof(t *testing.T) { for ti, testVector := range mtTestVectors { t.Run(fmt.Sprintf("Test vector %d", ti), func(t *testing.T) { - path := t.TempDir() - dbPrefix := "foo" - tableCfgFunc := func(defaultBuckets kv.TableCfg) kv.TableCfg { - cfg := kv.TableCfg{} - AddTables(cfg, dbPrefix) - return cfg - } - db, err := mdbx.NewMDBX(nil). - Path(path). - WithTableCfg(tableCfgFunc). - Open() + dbPath := path.Join(t.TempDir(), "tmp.db") + err := migrations.RunMigrations(dbPath) require.NoError(t, err) - tree, err := NewAppendOnlyTree(context.Background(), db, dbPrefix) + db, err := db.NewSQLiteDB(dbPath) require.NoError(t, err) + tree := NewAppendOnlyTree(db) - leaves := []Leaf{} + tx, err := db.BeginTx(ctx, nil) + require.NoError(t, err) for li, leaf := range testVector.Deposits { - leaves = append(leaves, Leaf{ + err = tree.AddLeaf(tx, uint64(li), 0, Leaf{ Index: uint32(li), Hash: leaf.Hash(), }) + require.NoError(t, err) } - tx, err := db.BeginRw(ctx) - require.NoError(t, err) - _, err = tree.AddLeaves(tx, leaves) - require.NoError(t, err) require.NoError(t, tx.Commit()) - txRo, err := tree.db.BeginRo(ctx) - require.NoError(t, err) - _, actualRoot, err := tree.getLastIndexAndRootWithTx(txRo) + root, err := tree.GetLastRoot(ctx) require.NoError(t, err) - txRo.Rollback() expectedRoot := common.HexToHash(testVector.ExpectedRoot) - require.Equal(t, expectedRoot, actualRoot) + require.Equal(t, expectedRoot, root.Hash) proof, err := tree.GetProof(ctx, testVector.Index, expectedRoot) require.NoError(t, err) diff --git a/tree/updatabletree.go b/tree/updatabletree.go index 5c54deb1..bae067ba 100644 --- a/tree/updatabletree.go +++ b/tree/updatabletree.go @@ -1,70 +1,29 @@ package tree import ( - "context" - "math" - - dbCommon "github.com/0xPolygon/cdk/common" - "github.com/ethereum/go-ethereum/common" - "github.com/ledgerwatch/erigon-lib/kv" + "database/sql" ) // UpdatableTree is a tree that have updatable leaves, and doesn't need to have sequential inserts type UpdatableTree struct { *Tree - lastRoot common.Hash } // NewUpdatableTree returns an UpdatableTree -func NewUpdatableTree(ctx context.Context, db kv.RwDB, dbPrefix string) (*UpdatableTree, error) { - // TODO: Load last root - t := newTree(db, dbPrefix) - tx, err := t.db.BeginRw(ctx) - if err != nil { - return nil, err - } - defer tx.Rollback() - rootIndex, root, err := t.getLastIndexAndRootWithTx(tx) - if err != nil { - return nil, err - } - if rootIndex == -1 { - root = t.zeroHashes[DefaultHeight] - } +func NewUpdatableTree(db *sql.DB) (*UpdatableTree, error) { + t := newTree(db) ut := &UpdatableTree{ - Tree: t, - lastRoot: root, + Tree: t, } return ut, nil } -// UpseartLeaves inserts or updates a list of leaves. The root index will be used to index the resulting -// root after performing all the operations. Root index must be greater than the last used root index, -// but doesn't need to be sequential. Great for relating block nums and roots :) -// It returns a function that must be called to rollback the changes done by this interaction -func (t *UpdatableTree) UpseartLeaves(tx kv.RwTx, leaves []Leaf, rootIndex uint64) (func(), error) { - if len(leaves) == 0 { - return func() {}, nil - } - rootBackup := t.lastRoot - rollback := func() { - t.lastRoot = rootBackup - } - - for _, l := range leaves { - if err := t.upsertLeaf(tx, l); err != nil { - return rollback, err - } - } - - if err := t.storeRoot(tx, rootIndex, t.lastRoot); err != nil { - return rollback, err +func (t *UpdatableTree) UpsertLeaf(tx *sql.Tx, blockNum, blockPosition uint64, leaf Leaf) error { + root, err := t.getLastRootWithTx(tx) + if err != nil { + return err } - return rollback, nil -} - -func (t *UpdatableTree) upsertLeaf(tx kv.RwTx, leaf Leaf) error { - siblings, _, err := t.getSiblings(tx, leaf.Index, t.lastRoot) + siblings, _, err := t.getSiblings(tx, leaf.Index, root.Hash) if err != nil { return err } @@ -74,67 +33,24 @@ func (t *UpdatableTree) upsertLeaf(tx kv.RwTx, leaf Leaf) error { var parent treeNode if leaf.Index&(1< 0 { // Add child to the right - parent = treeNode{ - left: siblings[h], - right: currentChildHash, - } + parent = newTreeNode(siblings[h], currentChildHash) } else { // Add child to the left - parent = treeNode{ - left: currentChildHash, - right: siblings[h], - } + parent = newTreeNode(currentChildHash, siblings[h]) } - currentChildHash = parent.hash() + currentChildHash = parent.Hash newNodes = append(newNodes, parent) } - + if err := t.storeRoot(tx, Root{ + Hash: currentChildHash, + Index: leaf.Index, + BlockNum: blockNum, + BlockPosition: blockPosition, + }); err != nil { + return err + } if err := t.storeNodes(tx, newNodes); err != nil { return err } - t.lastRoot = currentChildHash return nil } - -// Reorg deletes all the data relevant from firstReorgedIndex (includded) and onwards -// and prepares the tree tfor being used as it was at firstReorgedIndex-1. -// It returns a function that must be called to rollback the changes done by this interaction -func (t *UpdatableTree) Reorg(tx kv.RwTx, firstReorgedIndex uint64) (func(), error) { - iter, err := tx.RangeDescend( - t.rootTable, - dbCommon.Uint64ToBytes(math.MaxUint64), - dbCommon.Uint64ToBytes(0), - 0, - ) - if err != nil { - return func() {}, err - } - rootBackup := t.lastRoot - rollback := func() { - t.lastRoot = rootBackup - } - - for lastIndexBytes, rootBytes, err := iter.Next(); lastIndexBytes != nil; lastIndexBytes, rootBytes, err = iter.Next() { - if err != nil { - return rollback, err - } - - if dbCommon.BytesToUint64(lastIndexBytes) >= firstReorgedIndex { - if err := tx.Delete(t.rootTable, lastIndexBytes); err != nil { - return rollback, err - } - } else { - t.lastRoot = common.Hash(rootBytes) - return rollback, nil - } - } - - // no root found after reorg, going back to empty tree - t.lastRoot = t.zeroHashes[DefaultHeight] - return rollback, nil -} - -// GetRootByRootIndex returns the root of the tree as it was right after adding the leaf with index -func (t *UpdatableTree) GetRootByRootIndex(tx kv.Tx, rootIndex uint64) (common.Hash, error) { - return t.getRootByIndex(tx, rootIndex) -} From 07d657175fd693c50e4c69b493da2d3f1847445a Mon Sep 17 00:00:00 2001 From: Arnau Date: Tue, 3 Sep 2024 21:29:37 +0200 Subject: [PATCH 11/31] wip --- bridgesync/bridgesync.go | 15 +- bridgesync/e2e_test.go | 8 +- bridgesync/migrations/bridgesync0001.sql | 8 +- bridgesync/migrations/migrations.go | 11 +- bridgesync/processor.go | 247 +++++++++-------------- bridgesync/processor_test.go | 188 +++++++++++++---- l1bridge2infoindexsync/downloader.go | 5 +- l1bridge2infoindexsync/driver.go | 4 +- l1infotreesync/e2e_test.go | 8 +- l1infotreesync/l1infotreesync.go | 18 +- l1infotreesync/processor.go | 88 ++++---- lastgersync/evmdownloader.go | 6 +- tmp.sqlite | Bin 0 -> 57344 bytes tmp.sqlite-journal | Bin 0 -> 29240 bytes tree/migrations/migrations.go | 2 +- tree/tree.go | 53 +++-- 16 files changed, 359 insertions(+), 302 deletions(-) create mode 100644 tmp.sqlite create mode 100644 tmp.sqlite-journal diff --git a/bridgesync/bridgesync.go b/bridgesync/bridgesync.go index 220c33fd..0967e760 100644 --- a/bridgesync/bridgesync.go +++ b/bridgesync/bridgesync.go @@ -6,6 +6,7 @@ import ( "github.com/0xPolygon/cdk/etherman" "github.com/0xPolygon/cdk/sync" + "github.com/0xPolygon/cdk/tree" "github.com/ethereum/go-ethereum/common" ) @@ -97,7 +98,7 @@ func newBridgeSync( maxRetryAttemptsAfterError int, syncFullClaims bool, ) (*BridgeSync, error) { - processor, err := newProcessor(ctx, dbPath, l1OrL2ID) + processor, err := newProcessor(dbPath, l1OrL2ID) if err != nil { return nil, err } @@ -155,12 +156,16 @@ func (s *BridgeSync) GetLastProcessedBlock(ctx context.Context) (uint64, error) return s.processor.GetLastProcessedBlock(ctx) } -func (s *BridgeSync) GetBridgeIndexByRoot(ctx context.Context, root common.Hash) (uint32, error) { - return s.processor.exitTree.GetIndexByRoot(ctx, root) +func (s *BridgeSync) GetBridgeRootByHash(ctx context.Context, root common.Hash) (tree.Root, error) { + return s.processor.exitTree.GetRootByHash(ctx, root) } -func (s *BridgeSync) GetClaimsAndBridges(ctx context.Context, fromBlock, toBlock uint64) ([]Event, error) { - return s.processor.GetClaimsAndBridges(ctx, fromBlock, toBlock) +func (s *BridgeSync) GetClaims(ctx context.Context, fromBlock, toBlock uint64) ([]Claim, error) { + return s.processor.GetClaims(ctx, fromBlock, toBlock) +} + +func (s *BridgeSync) GetBridges(ctx context.Context, fromBlock, toBlock uint64) ([]Bridge, error) { + return s.processor.GetBridges(ctx, fromBlock, toBlock) } func (s *BridgeSync) GetProof(ctx context.Context, depositCount uint32, localExitRoot common.Hash) ([32]common.Hash, error) { diff --git a/bridgesync/e2e_test.go b/bridgesync/e2e_test.go index 6eff5548..b61c4ca3 100644 --- a/bridgesync/e2e_test.go +++ b/bridgesync/e2e_test.go @@ -107,14 +107,8 @@ func TestBridgeEventE2E(t *testing.T) { // Get bridges lastBlock, err := client.Client().BlockNumber(ctx) require.NoError(t, err) - events, err := syncer.GetClaimsAndBridges(ctx, 0, lastBlock) + actualBridges, err := syncer.GetBridges(ctx, 0, lastBlock) require.NoError(t, err) - actualBridges := []bridgesync.Bridge{} - for _, event := range events { - if event.Bridge != nil { - actualBridges = append(actualBridges, *event.Bridge) - } - } // Assert bridges require.Equal(t, expectedBridges, actualBridges) diff --git a/bridgesync/migrations/bridgesync0001.sql b/bridgesync/migrations/bridgesync0001.sql index 1901fb2d..9f544917 100644 --- a/bridgesync/migrations/bridgesync0001.sql +++ b/bridgesync/migrations/bridgesync0001.sql @@ -8,10 +8,9 @@ CREATE TABLE block ( num BIGINT PRIMARY KEY ); -CREATE TABLE claim ( +CREATE TABLE bridge ( block_num INTEGER NOT NULL REFERENCES block (num) ON DELETE CASCADE, block_pos INTEGER NOT NULL, - leaf_type INTEGER NOT NULL, origin_network INTEGER NOT NULL, origin_address VARCHAR NOT NULL, @@ -20,14 +19,12 @@ CREATE TABLE claim ( amount DECIMAL(78, 0) NOT NULL, metadata BLOB, deposit_count INTEGER NOT NULL, - PRIMARY KEY (block_num, block_pos) ); -CREATE TABLE bridge ( +CREATE TABLE claim ( block_num BIGINT NOT NULL REFERENCES block (block_num) ON DELETE CASCADE, block_pos BIGINT NOT NULL, - global_index DECIMAL(78, 0) NOT NULL, origin_network INTEGER NOT NULL, origin_address VARCHAR NOT NULL, @@ -41,6 +38,5 @@ CREATE TABLE bridge ( destination_network INTEGER NOT NULL, metadata BLOB, is_message BOOLEAN, - PRIMARY KEY (block_num, block_pos) ); \ No newline at end of file diff --git a/bridgesync/migrations/migrations.go b/bridgesync/migrations/migrations.go index e4a5d4ff..8050d422 100644 --- a/bridgesync/migrations/migrations.go +++ b/bridgesync/migrations/migrations.go @@ -4,6 +4,7 @@ import ( "strings" "github.com/0xPolygon/cdk/db" + treeMigrations "github.com/0xPolygon/cdk/tree/migrations" migrate "github.com/rubenv/sql-migrate" _ "embed" @@ -15,10 +16,10 @@ const upDownSeparator = "-- +migrate Up" var mig001 string var mig001splitted = strings.Split(mig001, upDownSeparator) -var Migrations = &migrate.MemoryMigrationSource{ +var bridgeMigrations = &migrate.MemoryMigrationSource{ Migrations: []*migrate.Migration{ { - Id: "001", + Id: "bridgesync001", Up: []string{mig001splitted[1]}, Down: []string{mig001splitted[0]}, }, @@ -26,5 +27,9 @@ var Migrations = &migrate.MemoryMigrationSource{ } func RunMigrations(dbPath string) error { - return db.RunMigrations(dbPath, Migrations) + bridgeMigrations.Migrations = append( + bridgeMigrations.Migrations, + treeMigrations.Migrations.Migrations..., + ) + return db.RunMigrations(dbPath, bridgeMigrations) } diff --git a/bridgesync/processor.go b/bridgesync/processor.go index 45a43052..ff9face4 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -4,44 +4,36 @@ import ( "context" "database/sql" "encoding/binary" - "encoding/json" "errors" "math/big" - dbCommon "github.com/0xPolygon/cdk/common" "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/log" "github.com/0xPolygon/cdk/sync" "github.com/0xPolygon/cdk/tree" "github.com/ethereum/go-ethereum/common" "github.com/iden3/go-iden3-crypto/keccak256" - "github.com/ledgerwatch/erigon-lib/kv" - "github.com/ledgerwatch/erigon-lib/kv/mdbx" "github.com/russross/meddler" _ "modernc.org/sqlite" ) -const ( - eventsTableSufix = "-events" - lastBlockTableSufix = "-lastBlock" -) - var ( ErrBlockNotProcessed = errors.New("given block(s) have not been processed yet") ErrNotFound = errors.New("not found") - lastBlockKey = []byte("lb") ) // Bridge is the representation of a bridge event type Bridge struct { - LeafType uint8 - OriginNetwork uint32 - OriginAddress common.Address - DestinationNetwork uint32 - DestinationAddress common.Address - Amount *big.Int - Metadata []byte - DepositCount uint32 + BlockNum uint64 `meddler:"block_num"` + BlockPos uint64 `meddler:"block_pos"` + LeafType uint8 `meddler:"leaf_type"` + OriginNetwork uint32 `meddler:"origin_network"` + OriginAddress common.Address `meddler:"origin_address"` + DestinationNetwork uint32 `meddler:"destination_network"` + DestinationAddress common.Address `meddler:"destination_address"` + Amount *big.Int `meddler:"amount"` + Metadata []byte `meddler:"metadata"` + DepositCount uint32 `meddler:"deposit_count"` } // Hash returns the hash of the bridge event as expected by the exit tree @@ -73,76 +65,73 @@ func (b *Bridge) Hash() common.Hash { // Claim representation of a claim event type Claim struct { - BlockNum uint64 - BlockPos uint64 - // From claim event - GlobalIndex *big.Int - OriginNetwork uint32 - OriginAddress common.Address - DestinationAddress common.Address - Amount *big.Int - // From call data - ProofLocalExitRoot [tree.DefaultHeight]common.Hash - ProofRollupExitRoot [tree.DefaultHeight]common.Hash - MainnetExitRoot common.Hash - RollupExitRoot common.Hash - GlobalExitRoot common.Hash - DestinationNetwork uint32 - Metadata []byte - // Meta - IsMessage bool + BlockNum uint64 `meddler:"block_num"` + BlockPos uint64 `meddler:"block_pos"` + GlobalIndex *big.Int `meddler:"global_index"` + OriginNetwork uint32 `meddler:"origin_network"` + OriginAddress common.Address `meddler:"origin_address"` + DestinationAddress common.Address `meddler:"destination_address"` + Amount *big.Int `meddler:"amount"` + ProofLocalExitRoot [tree.DefaultHeight]common.Hash `meddler:"proof_local_exit_root"` + ProofRollupExitRoot [tree.DefaultHeight]common.Hash `meddler:"proof_rollup_exit_root"` + MainnetExitRoot common.Hash `meddler:"mainnet_exit_root"` + RollupExitRoot common.Hash `meddler:"rollup_exit_root"` + GlobalExitRoot common.Hash `meddler:"global_exit_root"` + DestinationNetwork uint32 `meddler:"destination_network"` + Metadata []byte `meddler:"metadata"` + IsMessage bool `meddler:"is_message"` } // Event combination of bridge and claim events type Event struct { + Pos uint64 Bridge *Bridge Claim *Claim } type processor struct { - db *sql.DB - eventsTable string - lastBlockTable string - exitTree *tree.AppendOnlyTree - log *log.Logger + db *sql.DB + exitTree *tree.AppendOnlyTree + log *log.Logger } -func newProcessor(ctx context.Context, dbPath, dbPrefix string) (*processor, error) { +func newProcessor(dbPath, dbPrefix string) (*processor, error) { db, err := db.NewSQLiteDB(dbPath) if err != nil { return nil, err } - eventsTable := dbPrefix + eventsTableSufix - lastBlockTable := dbPrefix + lastBlockTableSufix logger := log.WithFields("bridge-syncer", dbPrefix) - tableCfgFunc := func(defaultBuckets kv.TableCfg) kv.TableCfg { - cfg := kv.TableCfg{} - tree.AddTables(cfg, dbPrefix) - return cfg - } - treeDB, err := mdbx.NewMDBX(nil). - Path(dbPath). - WithTableCfg(tableCfgFunc). - Open() - exitTree, err := tree.NewAppendOnlyTree(ctx, treeDB, dbPrefix) - if err != nil { - return nil, err - } + exitTree := tree.NewAppendOnlyTree(db) return &processor{ - db: db, - eventsTable: eventsTable, - lastBlockTable: lastBlockTable, - exitTree: exitTree, - log: logger, + db: db, + exitTree: exitTree, + log: logger, }, nil } -// GetClaimsAndBridges returns the claims and bridges occurred between fromBlock, toBlock both included. -// If toBlock has not been porcessed yet, ErrBlockNotProcessed will be returned func (p *processor) GetBridges( ctx context.Context, fromBlock, toBlock uint64, ) ([]Bridge, error) { - return nil, nil + tx, err := p.db.BeginTx(ctx, nil) + if err != nil { + return nil, err + } + defer tx.Rollback() + + err = p.isBlockProcessed(tx, toBlock) + if err != nil { + return nil, err + } + + bridges := []Bridge{} + err = meddler.QueryAll(tx, &bridges, ` + SELECT * FROM bridge + WHERE block_num >= $1 AND block_num <= $2; + `, fromBlock, toBlock) + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrNotFound + } + return bridges, err } func (p *processor) GetClaims( @@ -154,42 +143,33 @@ func (p *processor) GetClaims( } defer tx.Rollback() - lpb, err := p.getLastProcessedBlockWithTx(tx) + err = p.isBlockProcessed(tx, toBlock) if err != nil { return nil, err } - if lpb < toBlock { - return nil, ErrBlockNotProcessed - } - rows, err := tx.Query(` - SELECT - block_num, - block_pos, - global_index, - origin_network, - origin_address, - destination_address, - amount, - proof_local_exit_root, - proof_rollup_exit_root, - mainnet_exit_root, - rollup_exit_root, - global_exit_root, - destination_network, - is_message - metadata, - FROM claim + claims := []Claim{} + err = meddler.QueryAll(tx, &claims, ` + SELECT * FROM claim WHERE block_num >= $1 AND block_num <= $2; - `) - if err != nil { - return nil, err + `, fromBlock, toBlock) + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrNotFound } - claims := []Claim{} - err = meddler.ScanAll(rows, claims) return claims, err } +func (p *processor) isBlockProcessed(tx *sql.Tx, blockNum uint64) error { + lpb, err := p.getLastProcessedBlockWithTx(tx) + if err != nil { + return err + } + if lpb < blockNum { + return ErrBlockNotProcessed + } + return nil +} + // GetLastProcessedBlock returns the last processed block by the processor, including blocks // that don't have events func (p *processor) GetLastProcessedBlock(ctx context.Context) (uint64, error) { @@ -205,6 +185,9 @@ func (p *processor) getLastProcessedBlockWithTx(tx *sql.Tx) (uint64, error) { var lastProcessedBlock uint64 row := tx.QueryRow("SELECT num FROM BLOCK ORDER BY num DESC LIMIT 1;") err := row.Scan(&lastProcessedBlock) + if errors.Is(err, sql.ErrNoRows) { + return 0, nil + } return lastProcessedBlock, err } @@ -223,24 +206,7 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { } }() - row := tx.QueryRow(` - SELECT deposit_count - FROM bridge - WHERE block_num >= $1 - ORDER BY (block_num, block_pos) ASC - LIMIT 1; - `) - var firstDepositCountReorged int - err = row.Scan(&firstDepositCountReorged) - if err != nil { - if errors.Is(err, sql.ErrNoRows) { - firstDepositCountReorged = -1 - } else { - return err - } - } - - _, err = tx.Exec(`DELETE FROM block WHERE block >= $1;`, firstReorgedBlock) + _, err = tx.Exec(`DELETE FROM block WHERE num >= $1;`, firstReorgedBlock) if err != nil { if errRllbck := tx.Rollback(); errRllbck != nil { log.Errorf("error while rolling back tx %v", errRllbck) @@ -248,20 +214,10 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { return err } - exitTreeRollback := func() {} - treeTx, err := p.exitTree.BeginRw(ctx) - if err != nil { + if err = p.exitTree.Reorg(tx, firstReorgedBlock); err != nil { return err } - if firstDepositCountReorged != -1 { - if exitTreeRollback, err = p.exitTree.Reorg(treeTx, uint32(firstDepositCountReorged)); err != nil { - tx.Rollback() - exitTreeRollback() - return err - } - } if err := tx.Commit(); err != nil { - exitTreeRollback() return err } return nil @@ -274,7 +230,6 @@ func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { if err != nil { return err } - var exitTreeRollback func() defer func() { if err != nil { if errRllbck := tx.Rollback(); errRllbck != nil { @@ -283,52 +238,36 @@ func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { } }() - leaves := []tree.Leaf{} - if len(block.Events) > 0 { - events := []Event{} - for _, e := range block.Events { - event := e.(Event) - events = append(events, event) - if event.Bridge != nil { - leaves = append(leaves, tree.Leaf{ - Index: event.Bridge.DepositCount, - Hash: event.Bridge.Hash(), - }) - } - } + for _, e := range block.Events { if _, err := tx.Exec(`INSERT INTO block (num) VALUES ($1)`, block.Num); err != nil { return err } - value, err := json.Marshal(events) - if err != nil { - tx.Rollback() - return err + event := e.(Event) + if event.Bridge != nil { + if err = p.exitTree.AddLeaf(tx, block.Num, event.Pos, tree.Leaf{ + Index: event.Bridge.DepositCount, + Hash: event.Bridge.Hash(), + }); err != nil { + return err + } + if err = meddler.Insert(tx, "bridge", event.Bridge); err != nil { + return err + } } - if err := tx.Put(p.eventsTable, dbCommon.Uint64ToBytes(block.Num), value); err != nil { - tx.Rollback() - return err + if event.Claim != nil { + if err = meddler.Insert(tx, "claim", event.Claim); err != nil { + return err + } } } - exitTreeRollback, err := p.exitTree.AddLeaves(tx, leaves) - if err != nil { - tx.Rollback() - exitTreeRollback() - return err - } if err := tx.Commit(); err != nil { - exitTreeRollback() return err } p.log.Debugf("processed %d events until block %d", len(block.Events), block.Num) return nil } -func (p *processor) updateLastProcessedBlock(tx kv.RwTx, blockNum uint64) error { - blockNumBytes := dbCommon.Uint64ToBytes(blockNum) - return tx.Put(p.lastBlockTable, lastBlockKey, blockNumBytes) -} - func GenerateGlobalIndex(mainnetFlag bool, rollupIndex uint32, localExitRootIndex uint32) *big.Int { var ( globalIndexBytes []byte diff --git a/bridgesync/processor_test.go b/bridgesync/processor_test.go index 90fe74be..fe77a2d3 100644 --- a/bridgesync/processor_test.go +++ b/bridgesync/processor_test.go @@ -6,9 +6,11 @@ import ( "fmt" "math/big" "os" + "path" "slices" "testing" + migrationsBridge "github.com/0xPolygon/cdk/bridgesync/migrations" "github.com/0xPolygon/cdk/sync" "github.com/0xPolygon/cdk/tree/testvectors" "github.com/ethereum/go-ethereum/common" @@ -16,8 +18,11 @@ import ( ) func TestProceessor(t *testing.T) { - path := t.TempDir() - p, err := newProcessor(context.Background(), path, "foo") + path := path.Join("/Users/arnaub/Documents/polygon/cdk", "tmp.sqlite") + // path := path.Join(t.TempDir(), "tmp.sqlite") + err := migrationsBridge.RunMigrations(path) + require.NoError(t, err) + p, err := newProcessor(path, "foo") require.NoError(t, err) actions := []processAction{ // processed: ~ @@ -40,15 +45,24 @@ func TestProceessor(t *testing.T) { firstReorgedBlock: 1, expectedErr: nil, }, - &getClaimsAndBridgesAction{ + &getClaims{ p: p, description: "on an empty processor", ctx: context.Background(), fromBlock: 0, toBlock: 2, - expectedEvents: nil, + expectedClaims: nil, expectedErr: ErrBlockNotProcessed, }, + &getBridges{ + p: p, + description: "on an empty processor", + ctx: context.Background(), + fromBlock: 0, + toBlock: 2, + expectedBridges: nil, + expectedErr: ErrBlockNotProcessed, + }, &processBlockAction{ p: p, description: "block1", @@ -63,24 +77,42 @@ func TestProceessor(t *testing.T) { expectedLastProcessedBlock: 1, expectedErr: nil, }, - &getClaimsAndBridgesAction{ + &getClaims{ p: p, description: "after block1: range 0, 2", ctx: context.Background(), fromBlock: 0, toBlock: 2, - expectedEvents: nil, + expectedClaims: nil, expectedErr: ErrBlockNotProcessed, }, - &getClaimsAndBridgesAction{ + &getBridges{ + p: p, + description: "after block1: range 0, 2", + ctx: context.Background(), + fromBlock: 0, + toBlock: 2, + expectedBridges: nil, + expectedErr: ErrBlockNotProcessed, + }, + &getClaims{ p: p, description: "after block1: range 1, 1", ctx: context.Background(), fromBlock: 1, toBlock: 1, - expectedEvents: eventsToBridgeEvents(block1.Events), + expectedClaims: eventsToClaims(block1.Events), expectedErr: nil, }, + &getBridges{ + p: p, + description: "after block1: range 1, 1", + ctx: context.Background(), + fromBlock: 1, + toBlock: 1, + expectedBridges: eventsToBridges(block1.Events), + expectedErr: nil, + }, &reorgAction{ p: p, description: "after block1", @@ -88,15 +120,24 @@ func TestProceessor(t *testing.T) { expectedErr: nil, }, // processed: ~ - &getClaimsAndBridgesAction{ + &getClaims{ p: p, description: "after block1 reorged", ctx: context.Background(), fromBlock: 0, toBlock: 2, - expectedEvents: nil, + expectedClaims: nil, expectedErr: ErrBlockNotProcessed, }, + &getBridges{ + p: p, + description: "after block1 reorged", + ctx: context.Background(), + fromBlock: 0, + toBlock: 2, + expectedBridges: nil, + expectedErr: ErrBlockNotProcessed, + }, &processBlockAction{ p: p, description: "block1 (after it's reorged)", @@ -118,24 +159,45 @@ func TestProceessor(t *testing.T) { expectedLastProcessedBlock: 3, expectedErr: nil, }, - &getClaimsAndBridgesAction{ + &getClaims{ p: p, description: "after block3: range 2, 2", ctx: context.Background(), fromBlock: 2, toBlock: 2, - expectedEvents: []Event{}, + expectedClaims: []Claim{}, expectedErr: nil, }, - &getClaimsAndBridgesAction{ + &getClaims{ p: p, description: "after block3: range 1, 3", ctx: context.Background(), fromBlock: 1, toBlock: 3, - expectedEvents: append( - eventsToBridgeEvents(block1.Events), - eventsToBridgeEvents(block3.Events)..., + expectedClaims: append( + eventsToClaims(block1.Events), + eventsToClaims(block3.Events)..., + ), + expectedErr: nil, + }, + &getBridges{ + p: p, + description: "after block3: range 2, 2", + ctx: context.Background(), + fromBlock: 2, + toBlock: 2, + expectedBridges: []Bridge{}, + expectedErr: nil, + }, + &getBridges{ + p: p, + description: "after block3: range 1, 3", + ctx: context.Background(), + fromBlock: 1, + toBlock: 3, + expectedBridges: append( + eventsToBridges(block1.Events), + eventsToBridges(block3.Events)..., ), expectedErr: nil, }, @@ -194,41 +256,41 @@ func TestProceessor(t *testing.T) { expectedLastProcessedBlock: 5, expectedErr: nil, }, - &getClaimsAndBridgesAction{ + &getClaims{ p: p, description: "after block5: range 1, 3", ctx: context.Background(), fromBlock: 1, toBlock: 3, - expectedEvents: append( - eventsToBridgeEvents(block1.Events), - eventsToBridgeEvents(block3.Events)..., + expectedClaims: append( + eventsToClaims(block1.Events), + eventsToClaims(block3.Events)..., ), expectedErr: nil, }, - &getClaimsAndBridgesAction{ + &getClaims{ p: p, description: "after block5: range 4, 5", ctx: context.Background(), fromBlock: 4, toBlock: 5, - expectedEvents: append( - eventsToBridgeEvents(block4.Events), - eventsToBridgeEvents(block5.Events)..., + expectedClaims: append( + eventsToClaims(block4.Events), + eventsToClaims(block5.Events)..., ), expectedErr: nil, }, - &getClaimsAndBridgesAction{ + &getClaims{ p: p, description: "after block5: range 0, 5", ctx: context.Background(), fromBlock: 0, toBlock: 5, - expectedEvents: slices.Concat( - eventsToBridgeEvents(block1.Events), - eventsToBridgeEvents(block3.Events), - eventsToBridgeEvents(block4.Events), - eventsToBridgeEvents(block5.Events), + expectedClaims: slices.Concat( + eventsToClaims(block1.Events), + eventsToClaims(block3.Events), + eventsToClaims(block4.Events), + eventsToClaims(block5.Events), ), expectedErr: nil, }, @@ -324,29 +386,55 @@ type processAction interface { execute(t *testing.T) } -// GetClaimsAndBridges +// GetClaims -type getClaimsAndBridgesAction struct { +type getClaims struct { p *processor description string ctx context.Context fromBlock uint64 toBlock uint64 - expectedEvents []Event + expectedClaims []Claim expectedErr error } -func (a *getClaimsAndBridgesAction) method() string { - return "GetClaimsAndBridges" +func (a *getClaims) method() string { + return "GetClaims" } -func (a *getClaimsAndBridgesAction) desc() string { +func (a *getClaims) desc() string { return a.description } -func (a *getClaimsAndBridgesAction) execute(t *testing.T) { - actualEvents, actualErr := a.p.GetClaimsAndBridges(a.ctx, a.fromBlock, a.toBlock) - require.Equal(t, a.expectedEvents, actualEvents) +func (a *getClaims) execute(t *testing.T) { + actualEvents, actualErr := a.p.GetClaims(a.ctx, a.fromBlock, a.toBlock) + require.Equal(t, a.expectedClaims, actualEvents) + require.Equal(t, a.expectedErr, actualErr) +} + +// GetBridges + +type getBridges struct { + p *processor + description string + ctx context.Context + fromBlock uint64 + toBlock uint64 + expectedBridges []Bridge + expectedErr error +} + +func (a *getBridges) method() string { + return "GetBridges" +} + +func (a *getBridges) desc() string { + return a.description +} + +func (a *getBridges) execute(t *testing.T) { + actualEvents, actualErr := a.p.GetBridges(a.ctx, a.fromBlock, a.toBlock) + require.Equal(t, a.expectedBridges, actualEvents) require.Equal(t, a.expectedErr, actualErr) } @@ -418,12 +506,26 @@ func (a *processBlockAction) execute(t *testing.T) { require.Equal(t, a.expectedErr, actualErr) } -func eventsToBridgeEvents(events []interface{}) []Event { - bridgeEvents := []Event{} +func eventsToBridges(events []interface{}) []Bridge { + bridges := []Bridge{} + for _, event := range events { + e := event.(Event) + if e.Bridge != nil { + bridges = append(bridges, *e.Bridge) + } + } + return bridges +} + +func eventsToClaims(events []interface{}) []Claim { + claims := []Claim{} for _, event := range events { - bridgeEvents = append(bridgeEvents, event.(Event)) + e := event.(Event) + if e.Claim != nil { + claims = append(claims, *e.Claim) + } } - return bridgeEvents + return claims } func TestHashBridge(t *testing.T) { diff --git a/l1bridge2infoindexsync/downloader.go b/l1bridge2infoindexsync/downloader.go index f14fcf8e..c4e17ffa 100644 --- a/l1bridge2infoindexsync/downloader.go +++ b/l1bridge2infoindexsync/downloader.go @@ -6,6 +6,7 @@ import ( "github.com/0xPolygon/cdk/bridgesync" "github.com/0xPolygon/cdk/l1infotreesync" + "github.com/0xPolygon/cdk/tree" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rpc" @@ -61,6 +62,6 @@ func (d *downloader) getMainnetExitRootAtL1InfoTreeIndex(ctx context.Context, in return leaf.MainnetExitRoot, nil } -func (d *downloader) getBridgeIndex(ctx context.Context, mainnetExitRoot common.Hash) (uint32, error) { - return d.l1Bridge.GetBridgeIndexByRoot(ctx, mainnetExitRoot) +func (d *downloader) getBridgeIndex(ctx context.Context, mainnetExitRoot common.Hash) (tree.Root, error) { + return d.l1Bridge.GetBridgeRootByHash(ctx, mainnetExitRoot) } diff --git a/l1bridge2infoindexsync/driver.go b/l1bridge2infoindexsync/driver.go index ce681bf0..d64274ac 100644 --- a/l1bridge2infoindexsync/driver.go +++ b/l1bridge2infoindexsync/driver.go @@ -189,13 +189,13 @@ func (d *driver) getRelation(ctx context.Context, l1InfoIndex uint32) (bridge2L1 return bridge2L1InfoRelation{}, err } - bridgeIndex, err := d.downloader.getBridgeIndex(ctx, mer) + bridgeRoot, err := d.downloader.getBridgeIndex(ctx, mer) if err != nil { return bridge2L1InfoRelation{}, err } return bridge2L1InfoRelation{ - bridgeIndex: bridgeIndex, + bridgeIndex: bridgeRoot.Index, l1InfoTreeIndex: l1InfoIndex, }, nil } diff --git a/l1infotreesync/e2e_test.go b/l1infotreesync/e2e_test.go index 562f0e39..60b371c3 100644 --- a/l1infotreesync/e2e_test.go +++ b/l1infotreesync/e2e_test.go @@ -248,11 +248,11 @@ func TestStressAndReorgs(t *testing.T) { require.NoError(t, err) expectedGER, err := gerSc.GetLastGlobalExitRoot(&bind.CallOpts{Pending: false}) require.NoError(t, err) - index, actualL1InfoRoot, err := syncer.GetLastL1InfoTreeRootAndIndex(ctx) + lastRoot, err := syncer.GetLastL1InfoTreeRoot(ctx) require.NoError(t, err) - info, err := syncer.GetInfoByIndex(ctx, index) - require.NoError(t, err, fmt.Sprintf("index: %d", index)) + info, err := syncer.GetInfoByIndex(ctx, lastRoot.Index) + require.NoError(t, err, fmt.Sprintf("index: %d", lastRoot.Index)) - require.Equal(t, common.Hash(expectedL1InfoRoot), actualL1InfoRoot) + require.Equal(t, common.Hash(expectedL1InfoRoot), lastRoot.Hash) require.Equal(t, common.Hash(expectedGER), info.GlobalExitRoot, fmt.Sprintf("%+v", info)) } diff --git a/l1infotreesync/l1infotreesync.go b/l1infotreesync/l1infotreesync.go index 8cd3ee70..ca020ab6 100644 --- a/l1infotreesync/l1infotreesync.go +++ b/l1infotreesync/l1infotreesync.go @@ -116,24 +116,18 @@ func (s *L1InfoTreeSync) GetInfoByIndex(ctx context.Context, index uint32) (*L1I } // GetL1InfoTreeRootByIndex returns the root of the L1 info tree at the moment the leaf with the given index was added -func (s *L1InfoTreeSync) GetL1InfoTreeRootByIndex(ctx context.Context, index uint32) (common.Hash, error) { - tx, err := s.processor.db.BeginRo(ctx) - if err != nil { - return common.Hash{}, err - } - defer tx.Rollback() - - return s.processor.l1InfoTree.GetRootByIndex(tx, index) +func (s *L1InfoTreeSync) GetL1InfoTreeRootByIndex(ctx context.Context, index uint32) (tree.Root, error) { + return s.processor.l1InfoTree.GetRootByIndex(ctx, index) } // GetLastRollupExitRoot return the last rollup exit root processed -func (s *L1InfoTreeSync) GetLastRollupExitRoot(ctx context.Context) (common.Hash, error) { +func (s *L1InfoTreeSync) GetLastRollupExitRoot(ctx context.Context) (tree.Root, error) { return s.processor.rollupExitTree.GetLastRoot(ctx) } -// GetLastL1InfoTreeRootAndIndex return the last root and index processed from the L1 Info tree -func (s *L1InfoTreeSync) GetLastL1InfoTreeRootAndIndex(ctx context.Context) (uint32, common.Hash, error) { - return s.processor.l1InfoTree.GetLastIndexAndRoot(ctx) +// GetLastL1InfoTreeRoot return the last root and index processed from the L1 Info tree +func (s *L1InfoTreeSync) GetLastL1InfoTreeRoot(ctx context.Context) (tree.Root, error) { + return s.processor.l1InfoTree.GetLastRoot(ctx) } // GetLastProcessedBlock return the last processed block diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index b50bb745..191c5f35 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -130,8 +130,6 @@ func newProcessor(ctx context.Context, dbPath string) (*processor, error) { blockTable: {}, lastBlockTable: {}, } - tree.AddTables(cfg, dbPrefix+rollupExitTreeSuffix) - tree.AddTables(cfg, dbPrefix+l1InfoTreeSuffix) return cfg } db, err := mdbx.NewMDBX(nil). @@ -145,39 +143,37 @@ func newProcessor(ctx context.Context, dbPath string) (*processor, error) { db: db, } - l1InfoTree, err := tree.NewAppendOnlyTree(ctx, db, dbPrefix+l1InfoTreeSuffix) - if err != nil { - return nil, err - } - p.l1InfoTree = l1InfoTree - rollupExitTree, err := tree.NewUpdatableTree(ctx, db, dbPrefix+rollupExitTreeSuffix) - if err != nil { - return nil, err - } - p.rollupExitTree = rollupExitTree + // l1InfoTree, err := tree.NewAppendOnlyTree(ctx, db, dbPrefix+l1InfoTreeSuffix) + // p.l1InfoTree = l1InfoTree + // rollupExitTree, err := tree.NewUpdatableTree(ctx, db, dbPrefix+rollupExitTreeSuffix) + // if err != nil { + // return nil, err + // } + // p.rollupExitTree = rollupExitTree return p, nil } // GetL1InfoTreeMerkleProof creates a merkle proof for the L1 Info tree func (p *processor) GetL1InfoTreeMerkleProof(ctx context.Context, index uint32) ([32]ethCommon.Hash, ethCommon.Hash, error) { - tx, err := p.db.BeginRo(ctx) - if err != nil { - return tree.EmptyProof, ethCommon.Hash{}, err - } - defer tx.Rollback() - - root, err := p.l1InfoTree.GetRootByIndex(tx, index) - if err != nil { - return tree.EmptyProof, ethCommon.Hash{}, err - } - - proof, err := p.l1InfoTree.GetProof(ctx, index, root) - if err != nil { - return tree.EmptyProof, ethCommon.Hash{}, err - } - - // TODO: check if we need to return root or wat - return proof, root, nil + return tree.EmptyProof, ethCommon.Hash{}, nil + // tx, err := p.db.BeginRo(ctx) + // if err != nil { + // return tree.EmptyProof, ethCommon.Hash{}, err + // } + // defer tx.Rollback() + + // root, err := p.l1InfoTree.GetRootByIndex(tx, index) + // if err != nil { + // return tree.EmptyProof, ethCommon.Hash{}, err + // } + + // proof, err := p.l1InfoTree.GetProof(ctx, index, root) + // if err != nil { + // return tree.EmptyProof, ethCommon.Hash{}, err + // } + + // // TODO: check if we need to return root or wat + // return proof, root, nil } // GetLatestInfoUntilBlock returns the most recent L1InfoTreeLeaf that occurred before or at blockNum. @@ -316,12 +312,12 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { } var rollbackL1InfoTree func() if firstReorgedL1InfoTreeIndex != -1 { - rollbackL1InfoTree, err = p.l1InfoTree.Reorg(tx, uint32(firstReorgedL1InfoTreeIndex)) - if err != nil { - tx.Rollback() - rollbackL1InfoTree() - return err - } + // rollbackL1InfoTree, err = p.l1InfoTree.Reorg(tx, uint32(firstReorgedL1InfoTreeIndex)) + // if err != nil { + // tx.Rollback() + // rollbackL1InfoTree() + // return err + // } } if err := tx.Commit(); err != nil { rollbackL1InfoTree() @@ -417,19 +413,19 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { rollback() return err } - l1InfoTreeRollback, err = p.l1InfoTree.AddLeaves(tx, l1InfoTreeLeavesToAdd) - if err != nil { - rollback() - return err - } + // l1InfoTreeRollback, err = p.l1InfoTree.AddLeaves(tx, l1InfoTreeLeavesToAdd) + // if err != nil { + // rollback() + // return err + // } } if len(rollupExitTreeLeavesToAdd) > 0 { - rollupExitTreeRollback, err = p.rollupExitTree.UpseartLeaves(tx, rollupExitTreeLeavesToAdd, b.Num) - if err != nil { - rollback() - return err - } + // rollupExitTreeRollback, err = p.rollupExitTree.UpseartLeaves(tx, rollupExitTreeLeavesToAdd, b.Num) + // if err != nil { + // rollback() + // return err + // } } } if err := p.updateLastProcessedBlock(tx, b.Num); err != nil { diff --git a/lastgersync/evmdownloader.go b/lastgersync/evmdownloader.go index 717eb095..839188ef 100644 --- a/lastgersync/evmdownloader.go +++ b/lastgersync/evmdownloader.go @@ -118,16 +118,16 @@ func (d *downloader) Download(ctx context.Context, fromBlock uint64, downloadedC } func (d *downloader) getGERsFromIndex(ctx context.Context, fromL1InfoTreeIndex uint32) ([]Event, error) { - lastIndex, _, err := d.l1InfoTreesync.GetLastL1InfoTreeRootAndIndex(ctx) + lastRoot, err := d.l1InfoTreesync.GetLastL1InfoTreeRoot(ctx) if err == tree.ErrNotFound { return nil, nil } if err != nil { - return nil, fmt.Errorf("error calling GetLastL1InfoTreeRootAndIndex: %v", err) + return nil, fmt.Errorf("error calling GetLastL1InfoTreeRoot: %v", err) } gers := []Event{} - for i := fromL1InfoTreeIndex; i <= lastIndex; i++ { + for i := fromL1InfoTreeIndex; i <= lastRoot.Index; i++ { info, err := d.l1InfoTreesync.GetInfoByIndex(ctx, i) if err != nil { return nil, fmt.Errorf("error calling GetInfoByIndex: %v", err) diff --git a/tmp.sqlite b/tmp.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..c517ebe99e6f07b1cbc0222fe893aa60913a5972 GIT binary patch literal 57344 zcmeI&U2ob}7{GB}S_m`=m7>V1dUJ#{B`9fSlF+PU>rcIN!uTyE-zRo_tZg;t38;T*&ZPIRr{#LM!{rLEt-+9hSz&UzZvpiFrJ8sMH z#AfV%EFO=2EJQ38OUl=xd<~YA+_^J&Be(I${?D3n&M!2tsw?A6DRfR%M&fE{;BPpUFq#! zO9t*&pUc>HanXQCd1F!8!pgmr^5OE-cFLOT8-9!CSF(Q_So8z${qSWvttd+T=jDLp z%r>l6u$mh|2@dsDqV4b-Jy^zSD;nA-T0^T>v?CE*B39pBSrCVHaiG;SnIx6+QKft^ zVk8L$h4!~&WrtoDwsUIOdeF(y_yesX^QyMGy|XUVLIgSE$P}{LdfW8AaonrnHRJuZ zo*jf5&8BO1Bh?w??x2fhXw&R^R@?BCK##^x2sK(xuN|cL@aF#B^eT5`H=XM;b!1D; z*OsUI-6pT-7cOrfM!1e`_d3y#VMNQY+Oo~jlfmtW5x1`n0wQgp|tZd{ndQ~uum;bBcH*TdeA48%xgt%td$%M>bP3x&Cq z@>H2NUV^07i@_%IefDlzdGH|qqZ15-Q`c%i@?VT_X@i7MTW9At8|OKwe6Qxbkc22bkc2{(;~4aUTT(k6|E>0@D1+VoSVX$JGA zeij*Dx2xqR(Lc$XwNy&^=)ttS2{S-1hTC*Cneu1QZkRXzBp=LkcSf_uKi*H8kzWCk z>d1V(^S*oyr_W-rxqFj|r}_JCF8Q&ud9j+entAcH z;htR@?&?OVR1j@B%d~s8Ejq5%GTdu%WnQm~ywT~{mf6$|FE8W>Ha)9l7M>nd>_;pD4x_vgalv1%&novq1>QbHw literal 0 HcmV?d00001 diff --git a/tmp.sqlite-journal b/tmp.sqlite-journal new file mode 100644 index 0000000000000000000000000000000000000000..334dc5630828a090f86546f76ad26bb8dd1b9d3a GIT binary patch literal 29240 zcmeI(K@LDb3CjoQaVp?$A7&Ay$3u>ZcR&KgWGu@7ESFyvP3k@K#x1 zntOHHUAf0{5FkK+009C72oNAZfB=Eg0+|D> z_5n(_S#bmi5FkK+009C72oNAZ;1kFkV37kD2m%BM5FkK+009C72oNApUm$aU*}Z`J zy;dOs0t5&UAV7cs0RjXF5Xc;0vkzbv2oNAZfB*pk1PBlyK!8Affy@D#eSrGCRv`fb T1PBlyK!5-N0t5&U=sCaxG_Vrw literal 0 HcmV?d00001 diff --git a/tree/migrations/migrations.go b/tree/migrations/migrations.go index b1f1629f..98656ae9 100644 --- a/tree/migrations/migrations.go +++ b/tree/migrations/migrations.go @@ -18,7 +18,7 @@ var mig001splitted = strings.Split(mig001, upDownSeparator) var Migrations = &migrate.MemoryMigrationSource{ Migrations: []*migrate.Migration{ { - Id: "001", + Id: "tree001", Up: []string{mig001splitted[1]}, Down: []string{mig001splitted[0]}, }, diff --git a/tree/tree.go b/tree/tree.go index 558523d9..d79abb2a 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -58,19 +58,6 @@ func newTreeNode(left, right common.Hash) treeNode { } } -func (n *treeNode) MarshalBinary() ([]byte, error) { - return append(n.Left[:], n.Right[:]...), nil -} - -func (n *treeNode) UnmarshalBinary(data []byte) error { - if len(data) != 64 { - return fmt.Errorf("expected len %d, actual len %d", 64, len(data)) - } - n.Left = common.Hash(data[:32]) - n.Right = common.Hash(data[32:]) - return nil -} - func newTree(db *sql.DB) *Tree { t := &Tree{ db: db, @@ -218,6 +205,44 @@ func (t *Tree) getLastRootWithTx(tx *sql.Tx) (Root, error) { return root, nil } +// GetRootByIndex returns the root associated to the index +func (t *Tree) GetRootByIndex(ctx context.Context, index uint32) (Root, error) { + tx, err := t.db.BeginTx(ctx, nil) + if err != nil { + return Root{}, err + } + defer tx.Rollback() + + var root Root + err = meddler.QueryRow(tx, &root, `SELECT * FROM root WHERE position = $1;`, index) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return root, ErrNotFound + } + return root, err + } + return root, nil +} + +// GetRootByHash returns the root associated to the hash +func (t *Tree) GetRootByHash(ctx context.Context, hash common.Hash) (Root, error) { + tx, err := t.db.BeginTx(ctx, nil) + if err != nil { + return Root{}, err + } + defer tx.Rollback() + + var root Root + err = meddler.QueryRow(tx, &root, `SELECT * FROM root WHERE hash = $1;`, hash) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return root, ErrNotFound + } + return root, err + } + return root, nil +} + func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (common.Hash, error) { tx, err := t.db.BeginTx(ctx, nil) if err != nil { @@ -242,7 +267,7 @@ func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (com } // Reorg deletes all the data relevant from firstReorgedBlock (includded) and onwards -func (t *AppendOnlyTree) Reorg(tx *sql.Tx, firstReorgedBlock uint32) error { +func (t *AppendOnlyTree) Reorg(tx *sql.Tx, firstReorgedBlock uint64) error { _, err := tx.Exec(`DELETE FROM root WHERE block_num >= $1`, firstReorgedBlock) return err // NOTE: rht is not cleaned, this could be done in the future as optimization From d18914a4d59b39b4ce396876479913b59a38dac6 Mon Sep 17 00:00:00 2001 From: Arnau Date: Wed, 4 Sep 2024 11:07:47 +0200 Subject: [PATCH 12/31] wip --- bridgesync/bridgesync.go | 2 +- bridgesync/downloader.go | 8 +- bridgesync/processor.go | 48 +++++------ bridgesync/processor_test.go | 14 +++ db/meddler.go | 124 +++++++++++++++++++++++++++ db/sqlite.go | 4 +- l1bridge2infoindexsync/downloader.go | 4 +- l1infotreesync/l1infotreesync.go | 7 +- l1infotreesync/processor.go | 19 ++-- tmp.sqlite | Bin 57344 -> 61440 bytes tmp.sqlite-journal | Bin 29240 -> 0 bytes tree/appendonlytree.go | 17 ++-- tree/tree.go | 84 ++++++++---------- tree/tree_test.go | 22 ++--- tree/types/types.go | 27 ++++++ tree/updatabletree.go | 12 +-- 16 files changed, 276 insertions(+), 116 deletions(-) create mode 100644 db/meddler.go delete mode 100644 tmp.sqlite-journal create mode 100644 tree/types/types.go diff --git a/bridgesync/bridgesync.go b/bridgesync/bridgesync.go index 0967e760..f91be313 100644 --- a/bridgesync/bridgesync.go +++ b/bridgesync/bridgesync.go @@ -6,7 +6,7 @@ import ( "github.com/0xPolygon/cdk/etherman" "github.com/0xPolygon/cdk/sync" - "github.com/0xPolygon/cdk/tree" + tree "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" ) diff --git a/bridgesync/downloader.go b/bridgesync/downloader.go index 6366df2c..ee8a6df1 100644 --- a/bridgesync/downloader.go +++ b/bridgesync/downloader.go @@ -10,7 +10,7 @@ import ( "github.com/0xPolygon/cdk-contracts-tooling/contracts/etrog/polygonzkevmbridgev2" rpcTypes "github.com/0xPolygon/cdk-rpc/types" "github.com/0xPolygon/cdk/sync" - "github.com/0xPolygon/cdk/tree" + tree "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -61,6 +61,8 @@ func buildAppender(client EthClienter, bridge common.Address, syncFullClaims boo ) } b.Events = append(b.Events, Event{Bridge: &Bridge{ + BlockNum: b.Num, + BlockPos: uint64(l.Index), LeafType: bridge.LeafType, OriginNetwork: bridge.OriginNetwork, OriginAddress: bridge.OriginAddress, @@ -82,6 +84,8 @@ func buildAppender(client EthClienter, bridge common.Address, syncFullClaims boo ) } claim := &Claim{ + BlockNum: b.Num, + BlockPos: uint64(l.Index), GlobalIndex: claimEvent.GlobalIndex, OriginNetwork: claimEvent.OriginNetwork, OriginAddress: claimEvent.OriginAddress, @@ -104,6 +108,8 @@ func buildAppender(client EthClienter, bridge common.Address, syncFullClaims boo ) } claim := &Claim{ + BlockNum: b.Num, + BlockPos: uint64(l.Index), GlobalIndex: big.NewInt(int64(claimEvent.Index)), OriginNetwork: claimEvent.OriginNetwork, OriginAddress: claimEvent.OriginAddress, diff --git a/bridgesync/processor.go b/bridgesync/processor.go index ff9face4..0ca42701 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -11,6 +11,7 @@ import ( "github.com/0xPolygon/cdk/log" "github.com/0xPolygon/cdk/sync" "github.com/0xPolygon/cdk/tree" + "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" "github.com/iden3/go-iden3-crypto/keccak256" "github.com/russross/meddler" @@ -31,7 +32,7 @@ type Bridge struct { OriginAddress common.Address `meddler:"origin_address"` DestinationNetwork uint32 `meddler:"destination_network"` DestinationAddress common.Address `meddler:"destination_address"` - Amount *big.Int `meddler:"amount"` + Amount *big.Int `meddler:"amount,bigint"` Metadata []byte `meddler:"metadata"` DepositCount uint32 `meddler:"deposit_count"` } @@ -65,21 +66,21 @@ func (b *Bridge) Hash() common.Hash { // Claim representation of a claim event type Claim struct { - BlockNum uint64 `meddler:"block_num"` - BlockPos uint64 `meddler:"block_pos"` - GlobalIndex *big.Int `meddler:"global_index"` - OriginNetwork uint32 `meddler:"origin_network"` - OriginAddress common.Address `meddler:"origin_address"` - DestinationAddress common.Address `meddler:"destination_address"` - Amount *big.Int `meddler:"amount"` - ProofLocalExitRoot [tree.DefaultHeight]common.Hash `meddler:"proof_local_exit_root"` - ProofRollupExitRoot [tree.DefaultHeight]common.Hash `meddler:"proof_rollup_exit_root"` - MainnetExitRoot common.Hash `meddler:"mainnet_exit_root"` - RollupExitRoot common.Hash `meddler:"rollup_exit_root"` - GlobalExitRoot common.Hash `meddler:"global_exit_root"` - DestinationNetwork uint32 `meddler:"destination_network"` - Metadata []byte `meddler:"metadata"` - IsMessage bool `meddler:"is_message"` + BlockNum uint64 `meddler:"block_num"` + BlockPos uint64 `meddler:"block_pos"` + GlobalIndex *big.Int `meddler:"global_index,bigint"` + OriginNetwork uint32 `meddler:"origin_network"` + OriginAddress common.Address `meddler:"origin_address"` + DestinationAddress common.Address `meddler:"destination_address"` + Amount *big.Int `meddler:"amount,bigint"` + ProofLocalExitRoot types.Proof `meddler:"proof_local_exit_root,merkleproof"` + ProofRollupExitRoot types.Proof `meddler:"proof_rollup_exit_root,merkleproof"` + MainnetExitRoot common.Hash `meddler:"mainnet_exit_root"` + RollupExitRoot common.Hash `meddler:"rollup_exit_root"` + GlobalExitRoot common.Hash `meddler:"global_exit_root"` + DestinationNetwork uint32 `meddler:"destination_network"` + Metadata []byte `meddler:"metadata"` + IsMessage bool `meddler:"is_message"` } // Event combination of bridge and claim events @@ -148,7 +149,7 @@ func (p *processor) GetClaims( return nil, err } - claims := []Claim{} + claims := []*Claim{} err = meddler.QueryAll(tx, &claims, ` SELECT * FROM claim WHERE block_num >= $1 AND block_num <= $2; @@ -156,7 +157,7 @@ func (p *processor) GetClaims( if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } - return claims, err + return db.SlicePtrsToSlice(claims).([]Claim), err } func (p *processor) isBlockProcessed(tx *sql.Tx, blockNum uint64) error { @@ -208,9 +209,6 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { _, err = tx.Exec(`DELETE FROM block WHERE num >= $1;`, firstReorgedBlock) if err != nil { - if errRllbck := tx.Rollback(); errRllbck != nil { - log.Errorf("error while rolling back tx %v", errRllbck) - } return err } @@ -238,13 +236,13 @@ func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { } }() + if _, err := tx.Exec(`INSERT INTO block (num) VALUES ($1)`, block.Num); err != nil { + return err + } for _, e := range block.Events { - if _, err := tx.Exec(`INSERT INTO block (num) VALUES ($1)`, block.Num); err != nil { - return err - } event := e.(Event) if event.Bridge != nil { - if err = p.exitTree.AddLeaf(tx, block.Num, event.Pos, tree.Leaf{ + if err = p.exitTree.AddLeaf(tx, block.Num, event.Pos, types.Leaf{ Index: event.Bridge.DepositCount, Hash: event.Bridge.Hash(), }); err != nil { diff --git a/bridgesync/processor_test.go b/bridgesync/processor_test.go index fe77a2d3..7aaee223 100644 --- a/bridgesync/processor_test.go +++ b/bridgesync/processor_test.go @@ -11,6 +11,7 @@ import ( "testing" migrationsBridge "github.com/0xPolygon/cdk/bridgesync/migrations" + "github.com/0xPolygon/cdk/log" "github.com/0xPolygon/cdk/sync" "github.com/0xPolygon/cdk/tree/testvectors" "github.com/ethereum/go-ethereum/common" @@ -297,6 +298,7 @@ func TestProceessor(t *testing.T) { } for _, a := range actions { + log.Debugf("%s: %s", a.method(), a.desc()) t.Run(fmt.Sprintf("%s: %s", a.method(), a.desc()), a.execute) } } @@ -310,6 +312,8 @@ var ( Num: 1, Events: []interface{}{ Event{Bridge: &Bridge{ + BlockNum: 1, + BlockPos: 0, LeafType: 1, OriginNetwork: 1, OriginAddress: common.HexToAddress("01"), @@ -320,6 +324,8 @@ var ( DepositCount: 0, }}, Event{Claim: &Claim{ + BlockNum: 1, + BlockPos: 1, GlobalIndex: big.NewInt(1), OriginNetwork: 1, OriginAddress: common.HexToAddress("01"), @@ -332,6 +338,8 @@ var ( Num: 3, Events: []interface{}{ Event{Bridge: &Bridge{ + BlockNum: 3, + BlockPos: 0, LeafType: 2, OriginNetwork: 2, OriginAddress: common.HexToAddress("02"), @@ -342,6 +350,8 @@ var ( DepositCount: 1, }}, Event{Bridge: &Bridge{ + BlockNum: 3, + BlockPos: 1, LeafType: 3, OriginNetwork: 3, OriginAddress: common.HexToAddress("03"), @@ -361,6 +371,8 @@ var ( Num: 5, Events: []interface{}{ Event{Claim: &Claim{ + BlockNum: 4, + BlockPos: 0, GlobalIndex: big.NewInt(4), OriginNetwork: 4, OriginAddress: common.HexToAddress("04"), @@ -368,6 +380,8 @@ var ( Amount: big.NewInt(4), }}, Event{Claim: &Claim{ + BlockNum: 4, + BlockPos: 1, GlobalIndex: big.NewInt(5), OriginNetwork: 5, OriginAddress: common.HexToAddress("05"), diff --git a/db/meddler.go b/db/meddler.go new file mode 100644 index 00000000..a2ef9dbd --- /dev/null +++ b/db/meddler.go @@ -0,0 +1,124 @@ +package db + +import ( + "fmt" + "math/big" + "reflect" + "strings" + + tree "github.com/0xPolygon/cdk/tree/types" + "github.com/ethereum/go-ethereum/common" + "github.com/russross/meddler" + "modernc.org/sqlite" +) + +// initMeddler registers tags to be used to read/write from SQL DBs using meddler +func initMeddler() { + meddler.Default = meddler.SQLite + meddler.Register("bigint", BigIntMeddler{}) + meddler.Register("merkleproof", MerkleProofMeddler{}) +} + +func SQLiteErr(err error) (*sqlite.Error, bool) { + if sqliteErr, ok := err.(*sqlite.Error); ok { + return sqliteErr, true + } + if driverErr, ok := meddler.DriverErr(err); ok { + if sqliteErr, ok := driverErr.(*sqlite.Error); ok { + return sqliteErr, true + } + } + return nil, false +} + +// SliceToSlicePtrs converts any []Foo to []*Foo +func SliceToSlicePtrs(slice interface{}) interface{} { + v := reflect.ValueOf(slice) + vLen := v.Len() + typ := v.Type().Elem() + res := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(typ)), vLen, vLen) + for i := 0; i < vLen; i++ { + res.Index(i).Set(v.Index(i).Addr()) + } + return res.Interface() +} + +// SlicePtrsToSlice converts any []*Foo to []Foo +func SlicePtrsToSlice(slice interface{}) interface{} { + v := reflect.ValueOf(slice) + vLen := v.Len() + typ := v.Type().Elem().Elem() + res := reflect.MakeSlice(reflect.SliceOf(typ), vLen, vLen) + for i := 0; i < vLen; i++ { + res.Index(i).Set(v.Index(i).Elem()) + } + return res.Interface() +} + +// BigIntMeddler encodes or decodes the field value to or from JSON +type BigIntMeddler struct{} + +// PreRead is called before a Scan operation for fields that have the BigIntMeddler +func (b BigIntMeddler) PreRead(fieldAddr interface{}) (scanTarget interface{}, err error) { + // give a pointer to a byte buffer to grab the raw data + return new(string), nil +} + +// PostRead is called after a Scan operation for fields that have the BigIntMeddler +func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error { + ptr := scanTarget.(*string) + if ptr == nil { + return fmt.Errorf("BigIntMeddler.PostRead: nil pointer") + } + field := fieldPtr.(**big.Int) + var ok bool + *field, ok = new(big.Int).SetString(*ptr, 10) + if !ok { + return fmt.Errorf("big.Int.SetString failed on \"%v\"", *ptr) + } + return nil +} + +// PreWrite is called before an Insert or Update operation for fields that have the BigIntMeddler +func (b BigIntMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) { + field := fieldPtr.(*big.Int) + + return field.String(), nil +} + +// MerkleProofMeddler encodes or decodes the field value to or from JSON +type MerkleProofMeddler struct{} + +// PreRead is called before a Scan operation for fields that have the ProofMeddler +func (b MerkleProofMeddler) PreRead(fieldAddr interface{}) (scanTarget interface{}, err error) { + // give a pointer to a byte buffer to grab the raw data + return new(string), nil +} + +// PostRead is called after a Scan operation for fields that have the ProofMeddler +func (b MerkleProofMeddler) PostRead(fieldPtr, scanTarget interface{}) error { + ptr := scanTarget.(*string) + if ptr == nil { + return fmt.Errorf("ProofMeddler.PostRead: nil pointer") + } + field := fieldPtr.(*tree.Proof) + strHashes := strings.Split(*ptr, ",") + if len(strHashes) != int(tree.DefaultHeight) { + return fmt.Errorf("unexpected len of hashes: expected %d actual %d", tree.DefaultHeight, len(strHashes)) + } + for i, strHash := range strHashes { + field[i] = common.HexToHash(strHash) + } + return nil +} + +// PreWrite is called before an Insert or Update operation for fields that have the ProofMeddler +func (b MerkleProofMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) { + field := fieldPtr.(tree.Proof) + var s string + for _, f := range field { + s += f.Hex() + "," + } + s = strings.TrimSuffix(s, ",") + return s, nil +} diff --git a/db/sqlite.go b/db/sqlite.go index 1c0357af..d3417d58 100644 --- a/db/sqlite.go +++ b/db/sqlite.go @@ -3,13 +3,11 @@ package db import ( "database/sql" - "github.com/russross/meddler" _ "modernc.org/sqlite" ) // NewSQLiteDB creates a new SQLite DB func NewSQLiteDB(dbPath string) (*sql.DB, error) { - meddler.Default = meddler.SQLite - meddler.Mapper = meddler.SnakeCase + initMeddler() return sql.Open("sqlite", dbPath) } diff --git a/l1bridge2infoindexsync/downloader.go b/l1bridge2infoindexsync/downloader.go index c4e17ffa..73f50fd7 100644 --- a/l1bridge2infoindexsync/downloader.go +++ b/l1bridge2infoindexsync/downloader.go @@ -6,7 +6,7 @@ import ( "github.com/0xPolygon/cdk/bridgesync" "github.com/0xPolygon/cdk/l1infotreesync" - "github.com/0xPolygon/cdk/tree" + "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rpc" @@ -62,6 +62,6 @@ func (d *downloader) getMainnetExitRootAtL1InfoTreeIndex(ctx context.Context, in return leaf.MainnetExitRoot, nil } -func (d *downloader) getBridgeIndex(ctx context.Context, mainnetExitRoot common.Hash) (tree.Root, error) { +func (d *downloader) getBridgeIndex(ctx context.Context, mainnetExitRoot common.Hash) (types.Root, error) { return d.l1Bridge.GetBridgeRootByHash(ctx, mainnetExitRoot) } diff --git a/l1infotreesync/l1infotreesync.go b/l1infotreesync/l1infotreesync.go index ca020ab6..360e9d8a 100644 --- a/l1infotreesync/l1infotreesync.go +++ b/l1infotreesync/l1infotreesync.go @@ -8,6 +8,7 @@ import ( "github.com/0xPolygon/cdk/etherman" "github.com/0xPolygon/cdk/sync" "github.com/0xPolygon/cdk/tree" + "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" ) @@ -116,17 +117,17 @@ func (s *L1InfoTreeSync) GetInfoByIndex(ctx context.Context, index uint32) (*L1I } // GetL1InfoTreeRootByIndex returns the root of the L1 info tree at the moment the leaf with the given index was added -func (s *L1InfoTreeSync) GetL1InfoTreeRootByIndex(ctx context.Context, index uint32) (tree.Root, error) { +func (s *L1InfoTreeSync) GetL1InfoTreeRootByIndex(ctx context.Context, index uint32) (types.Root, error) { return s.processor.l1InfoTree.GetRootByIndex(ctx, index) } // GetLastRollupExitRoot return the last rollup exit root processed -func (s *L1InfoTreeSync) GetLastRollupExitRoot(ctx context.Context) (tree.Root, error) { +func (s *L1InfoTreeSync) GetLastRollupExitRoot(ctx context.Context) (types.Root, error) { return s.processor.rollupExitTree.GetLastRoot(ctx) } // GetLastL1InfoTreeRoot return the last root and index processed from the L1 Info tree -func (s *L1InfoTreeSync) GetLastL1InfoTreeRoot(ctx context.Context) (tree.Root, error) { +func (s *L1InfoTreeSync) GetLastL1InfoTreeRoot(ctx context.Context) (types.Root, error) { return s.processor.l1InfoTree.GetLastRoot(ctx) } diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index 191c5f35..86943565 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -11,6 +11,7 @@ import ( "github.com/0xPolygon/cdk/log" "github.com/0xPolygon/cdk/sync" "github.com/0xPolygon/cdk/tree" + treeTypes "github.com/0xPolygon/cdk/tree/types" ethCommon "github.com/ethereum/go-ethereum/common" "github.com/iden3/go-iden3-crypto/keccak256" "github.com/ledgerwatch/erigon-lib/kv" @@ -143,9 +144,9 @@ func newProcessor(ctx context.Context, dbPath string) (*processor, error) { db: db, } - // l1InfoTree, err := tree.NewAppendOnlyTree(ctx, db, dbPrefix+l1InfoTreeSuffix) + // l1InfoTree, err := treeTypes.NewAppendOnlyTree(ctx, db, dbPrefix+l1InfoTreeSuffix) // p.l1InfoTree = l1InfoTree - // rollupExitTree, err := tree.NewUpdatableTree(ctx, db, dbPrefix+rollupExitTreeSuffix) + // rollupExitTree, err := treeTypes.NewUpdatableTree(ctx, db, dbPrefix+rollupExitTreeSuffix) // if err != nil { // return nil, err // } @@ -158,18 +159,18 @@ func (p *processor) GetL1InfoTreeMerkleProof(ctx context.Context, index uint32) return tree.EmptyProof, ethCommon.Hash{}, nil // tx, err := p.db.BeginRo(ctx) // if err != nil { - // return tree.EmptyProof, ethCommon.Hash{}, err + // return treeTypes.EmptyProof, ethCommon.Hash{}, err // } // defer tx.Rollback() // root, err := p.l1InfoTree.GetRootByIndex(tx, index) // if err != nil { - // return tree.EmptyProof, ethCommon.Hash{}, err + // return treeTypes.EmptyProof, ethCommon.Hash{}, err // } // proof, err := p.l1InfoTree.GetProof(ctx, index, root) // if err != nil { - // return tree.EmptyProof, ethCommon.Hash{}, err + // return treeTypes.EmptyProof, ethCommon.Hash{}, err // } // // TODO: check if we need to return root or wat @@ -348,8 +349,8 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { rollupExitTreeRollback() l1InfoTreeRollback() } - l1InfoTreeLeavesToAdd := []tree.Leaf{} - rollupExitTreeLeavesToAdd := []tree.Leaf{} + l1InfoTreeLeavesToAdd := []treeTypes.Leaf{} + rollupExitTreeLeavesToAdd := []treeTypes.Leaf{} if len(b.Events) > 0 { var initialL1InfoIndex uint32 var l1InfoLeavesAdded uint32 @@ -379,7 +380,7 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { rollback() return err } - l1InfoTreeLeavesToAdd = append(l1InfoTreeLeavesToAdd, tree.Leaf{ + l1InfoTreeLeavesToAdd = append(l1InfoTreeLeavesToAdd, treeTypes.Leaf{ Index: leafToStore.Index, Hash: leafToStore.Hash(), }) @@ -387,7 +388,7 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { } if event.VerifyBatches != nil { - rollupExitTreeLeavesToAdd = append(rollupExitTreeLeavesToAdd, tree.Leaf{ + rollupExitTreeLeavesToAdd = append(rollupExitTreeLeavesToAdd, treeTypes.Leaf{ Index: event.VerifyBatches.RollupID - 1, Hash: event.VerifyBatches.ExitRoot, }) diff --git a/tmp.sqlite b/tmp.sqlite index c517ebe99e6f07b1cbc0222fe893aa60913a5972..5460eb72287cc80dd0459d6dc89be8bd0794e795 100644 GIT binary patch literal 61440 zcmeI53tUWF`^RURnr5cCh|QVzK!$1RSW+#({E2<0G0^51KcMkn_B|NP(g^Z6g1WoGX^d;j+Hto2>bTFpFr z>=`@8TdtO2Q98LN00AHX1b_e#XeN+EW9#!f zbf6|hs-;sDGF6zGcyNaJi9G#9n7`*>ZxKf9z(lBIds@|3yGnnnbF?x>u9hpK zkjTr&Uo>3ghc(v>3-Iw86Ci4;{uG5WBtjAu8%YQUdkrVFA9dOSEqkq0EE{VBI={cs zXWL2CT;hmY#I|OU3WZ2$FmIB+KA+F0E;7;}2~kMpk(veL6DXQpAE;=z12ww2w5l!U zCmJU56Zs4gjm0#lU_C#cX@iM+@BPCc0^=ga{p?rLq}vwFGq=amEMZ zg!?9iN~uu9Mr%u26p>PS6wzkwgBtfOioc(&5ome&09(5Xt!!vx&?ejl+(?;Pic8hf zCMPY+!QSG*M2qAxl1Ku&G*s4d2yG1(i@imjK25!^H4wET%dRQbBt!_=uxxA?biO

GMrZsq>YZfiOiS$3taJOZq26p=sY2#zO1%wlNThN#K7q1X`PH zBA}2-r%KfE(b|;$u56BE?JoJ-MD>|~ZzF=+>g6_^YRj6(L>t!H8V{cz3vGqXhmgT# znt4+aqBXw$UM&}-QY5wlEGtU`fBtK^YVRXi3Ui?_opq|wm|xeS*`)fN~r zf@NxXq|C-$ht3~k`#D^#yh((ucF>6T5)AZyff z00e*l5C8%|00{ht2@KSsb&gf5WHNz3=qPY>vKP483!E^a&`sd%CJ;EdIJ@=}3Nc%O zqdf00e*l5C8%|00;m9AOHmZsRRsYov9!43_6B1Yvw0819bhL z_|iXx*YHnm9@HBM00AHX1b_e#00KY&2mk>f00e*l5cm=S9jXo!UH^yA|6ig6$AAD3 z00KY&2mk>f00e*l5C8%|00{iE3D9UvCc6Gl<(;7r4=6wY2mk>f00e*l5C8%|00;m9 zAOHk_!2f#!PE-RXgUNIv{&6+8_G?w+wrf00e*l5C8%|;OinlT>o$S|Nol%|6TjK8V9Wb0zd!=00AHX1b_e#00KY& z2mk>f@J$e~qUw1wm<;Kf00e*l5cui{Skk$cH1b_e#00KY& z2mk>f00e*l5C8%|fFMAlHQoOYqj^wx>v&Gw5^fk*hqHmxmwk~P&ek>9XyC%S#8R;6 z%*{+U#$`qngQ1_LKY(6FkEXNqw(1Sky{fCyWz&8n3_t+_-yi`T(k?m-G9qbF?k>@kl#Q!4@^={DK4KiU#3&-D zb~1DEltjw7?YKGeLS}_^Rn{)IN4NeNUT2hVbIxYbW|!Ip&69__O|p8k`b3CurDdXT zLG05J5^sy0b+0`=3@XyXH=L@Nb*3uL!dQ0288<^-$gJEPafp_~TKI}$Jl28!OPy7t z@%H3P>dBX!(iH+mdhcqNh5NWxF~3jyDT(pmhh*;BI)y>X&x?AG+?t+tC~3(S3%o1x zLS`k#*G6P_W75@A0m0_y_a4YOf2;a;o2ZWb%h94k2i-!qOm(<-)Bei7U!&utd+!e` z(v6ds9|#n4(x!8E|7+HFj~(zX$P1a3BS(HL{VDi_AKkFw*00gm%ywkU_sB45LC(nE5|fI|@Xp8!nU%(K9d^ft zzT>_vwu+t*_h_ASoZ0!z$$bm!Mi-fwB+p-a@Vr`A`J&(RZH0DAXm@zHok?nZ+O#?0 zdmk>iR`qoLMZ6R8LS`j@_(S=`xUEGGhUtGlK~{8c>zh+EDUHuf#L7SejA}B9RXFjq zI{z16e6Htm4UuiX^srq6H_ zjn;<#(H=w>Ts)YUb#AvBxfUvdzUZ`o^H8 zuG@}hgeEXcLmOu5-Tl>td*2V|BQIoD96f`7WS@zi) z7;C-d0*i?ojLRuy&rI@Gx+&9&gU$v_o#rxK`CYZ4VRZTY^t;n>W8{U*%1-m#pwvfZ zQgQc}3!a`IQg1b-;@nx4Y?R_h6LoNP;nhDq=Pjsl&Jrzt|JXI(y+>_Yuf6@t@9(Nw zGBd+@wE8MtSofFeA#PHlBkJCBgPTQvxPfi!% z!&47nl{b5pjkwuRIC9pcPHsLI9=sYBy5)IZCEgKvA+u86&@STqbf3!eGcR9!*D3R; z@dk>!fh0h%=#R(Wm1Oj7$PMp#;AMbE{i>m_+;8_=;@-aV?Tz$vKh$)=?gz$|hHu6@ zATMNAbmuz!V0v%V#h1eSCSisuEJ7vXQJy4RynD^;TntBLj{tcA0~4yniSmQI_S zXyd@v+@!I`7_7c|D_;#`r0b z-aEOlGW1UA{@?WXCEW`fP+TSqdNXO=tyIrj4LO#o+G9QLu6>q(w?kgYtk|AnZQ7K- zFo=DaUwzr^mj^k8UWcA;O9(7t*x>1c#y!@3s(5};$Nw_TvK2n8@vR&1`@1*Z%l&KI z;+R>r@7J2+hR6$ zRFeaTdwV*T#4j#S2!3#97)zCLx7exI`1Br^a31nPX65HO)%V-Q9?6w$_hK%M^Hm(r zj^}RBUuM}avZo<~xA;X+=*}y}XI|)7h2N@3*xT_s>%zn6%U)Zye*ZeDY{J7M=Ws6a zLT2Ua&u@-C&B=Q#{^Q_*Gh@nFjHSQqc-NkBwdm92|zE*Tl-J!bjneNh6 zxupT#)iKv>c?oZ#bfy(AuRMfvkQXv5vpZz19#^8K_c5)ZihKOQEYz_qs?LADZ}8X~ z<^y(^RXHsyE_p0sJtC4JGd2IvEMqbFQbRQpb=}}q7 zY~cvC6K%u>C;UuGwW^`fh(9aBz2Y~4N&Q|ougc_C%oF^d`n*kB6WMM|;`pxZyJg8P zO?*A$N&O1k0C^#^qJGhD|DN@JHxCZWm^Z+8>+Q|r4oUIO-&dGl5l-Lf8tne2eBkWc z#ZbnTkVv^0I0E_QIpJ9Z))XCW_SRy@l)UB6U=`JBuNT>X0d-pbg` z_M_KWWRDKNKK}a+&dczUzb;oXj;_t$cIRs2-i&~^ItA&mfxa`QG3BL0dA|O)aVGLY zW<~$_oA% z>Z0-cE7bA#=7co#Ih~-#n~m%ADZ~}0(^hvc&bPhbwqH3H*GFE+tQ0a{oW7LLJ@T(h z%-ThIkFrwx9a|EVl;7U@%!)_t!+!`~kZ5suzHh0A@s0sg_rEu^-*GeM)t-(I4ELMO zvDm%NGz_OBFJxApG){W9K5KWZQ~yH#R`W`hG1WZs@W${fb=gnm)1&I zWnZp19dB)K&g^h*(^P-XtT}o~?U;8i*yDQ03z?NOE_RdcBzCJhrvKFI?!YS76^oV^ z8QB+ds?kz;-UFR?ETe9%ysx41{<%AvR}@qG-!umj{~<(RtUTA zF1RrwXnppUyRHj$^9ttSG~|WMir%vMr%pVImc*A@&cGM;Nm($mV;=R#L+j#wKjh^Lk@) zE2mJr=p6#Nf6PEi z;e_(?xYrDR;Wl!^IeXcq>|NYk-UntB?ozIZSI+*P^OjxDDdQ|=)AOHk_01yBIKmZ5;fp3C9cbYeq?D7DHL}b~0b0i{5&YK|- zS#G^65|O3GyC4x+X1g;IktL=(ArV<#*%XP$(!wT4M3&X%BN16r))q_|nFI{nrS-3wS_rgkL0kZf76L6>Urk)VZv=hp)UT#bp&=jp j6#lTcpa2%YLW@AlCd?PWqJ==q)_))_zKOJCb0hx;CX{X( delta 271 zcmZp8z}#?vd4e=6GXnzy-$Vs_M&^wP`tsVw3Py%j2If`<26`suW(MXa3fcxn1_lbw zuE8M+xwhH{dIqLu=H?crCdQL@$xEZEH#Iah#iHKS!qn2l)N+#ohrniGgO~gh1NbLh aU}0hq*eq!98pLDc1v&!3rIsWK<^TXRI72!B diff --git a/tmp.sqlite-journal b/tmp.sqlite-journal deleted file mode 100644 index 334dc5630828a090f86546f76ad26bb8dd1b9d3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29240 zcmeI(K@LDb3CjoQaVp?$A7&Ay$3u>ZcR&KgWGu@7ESFyvP3k@K#x1 zntOHHUAf0{5FkK+009C72oNAZfB=Eg0+|D> z_5n(_S#bmi5FkK+009C72oNAZ;1kFkV37kD2m%BM5FkK+009C72oNApUm$aU*}Z`J zy;dOs0t5&UAV7cs0RjXF5Xc;0vkzbv2oNAZfB*pk1PBlyK!8Affy@D#eSrGCRv`fb T1PBlyK!5-N0t5&U=sCaxG_Vrw diff --git a/tree/appendonlytree.go b/tree/appendonlytree.go index 0dac5051..550b9b5f 100644 --- a/tree/appendonlytree.go +++ b/tree/appendonlytree.go @@ -4,13 +4,14 @@ import ( "database/sql" "fmt" + "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" ) // AppendOnlyTree is a tree where leaves are added sequentially (by index) type AppendOnlyTree struct { *Tree - lastLeftCache [DefaultHeight]common.Hash + lastLeftCache [types.DefaultHeight]common.Hash lastIndex int64 } @@ -20,7 +21,7 @@ func NewAppendOnlyTree(db *sql.DB) *AppendOnlyTree { return &AppendOnlyTree{Tree: t} } -func (t *AppendOnlyTree) AddLeaf(tx *sql.Tx, blockNum, blockPosition uint64, leaf Leaf) error { +func (t *AppendOnlyTree) AddLeaf(tx *sql.Tx, blockNum, blockPosition uint64, leaf types.Leaf) error { if int64(leaf.Index) != t.lastIndex+1 { // rebuild cache if err := t.initCache(tx); err != nil { @@ -35,9 +36,9 @@ func (t *AppendOnlyTree) AddLeaf(tx *sql.Tx, blockNum, blockPosition uint64, lea } // Calculate new tree nodes currentChildHash := leaf.Hash - newNodes := []treeNode{} - for h := uint8(0); h < DefaultHeight; h++ { - var parent treeNode + newNodes := []types.TreeNode{} + for h := uint8(0); h < types.DefaultHeight; h++ { + var parent types.TreeNode if leaf.Index&(1< 0 { // Add child to the right parent = newTreeNode(t.lastLeftCache[h], currentChildHash) @@ -52,7 +53,7 @@ func (t *AppendOnlyTree) AddLeaf(tx *sql.Tx, blockNum, blockPosition uint64, lea } // store root - if err := t.storeRoot(tx, Root{ + if err := t.storeRoot(tx, types.Root{ Hash: currentChildHash, Index: leaf.Index, BlockNum: blockNum, @@ -70,7 +71,7 @@ func (t *AppendOnlyTree) AddLeaf(tx *sql.Tx, blockNum, blockPosition uint64, lea } func (t *AppendOnlyTree) initCache(tx *sql.Tx) error { - siblings := [DefaultHeight]common.Hash{} + siblings := [types.DefaultHeight]common.Hash{} lastRoot, err := t.getLastRootWithTx(tx) if err != nil { if err == ErrNotFound { @@ -84,7 +85,7 @@ func (t *AppendOnlyTree) initCache(tx *sql.Tx) error { currentNodeHash := lastRoot.Hash index := t.lastIndex // It starts in height-1 because 0 is the level of the leafs - for h := int(DefaultHeight - 1); h >= 0; h-- { + for h := int(types.DefaultHeight - 1); h >= 0; h-- { currentNode, err := t.getRHTNode(tx, currentNodeHash) if err != nil { return fmt.Errorf( diff --git a/tree/tree.go b/tree/tree.go index d79abb2a..5bee7c07 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -6,52 +6,31 @@ import ( "errors" "fmt" + "github.com/0xPolygon/cdk/db" + "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" "github.com/russross/meddler" "golang.org/x/crypto/sha3" -) - -const ( - DefaultHeight uint8 = 32 + sqlite3 "modernc.org/sqlite/lib" ) var ( - EmptyProof = Proof{} + EmptyProof = types.Proof{} ErrNotFound = errors.New("not found") ) -type Leaf struct { - Index uint32 - Hash common.Hash -} - -type Proof [DefaultHeight]common.Hash - -type Root struct { - Hash common.Hash `meddler:"hash"` - Index uint32 `meddler:"position"` - BlockNum uint64 `meddler:"block_num"` - BlockPosition uint64 `meddler:"block_position"` -} - type Tree struct { db *sql.DB zeroHashes []common.Hash } -type treeNode struct { - Hash common.Hash `meddler:"hash"` - Left common.Hash `meddler:"left"` - Right common.Hash `meddler:"right"` -} - -func newTreeNode(left, right common.Hash) treeNode { +func newTreeNode(left, right common.Hash) types.TreeNode { var hash common.Hash hasher := sha3.NewLegacyKeccak256() hasher.Write(left[:]) hasher.Write(right[:]) copy(hash[:], hasher.Sum(nil)) - return treeNode{ + return types.TreeNode{ Hash: hash, Left: left, Right: right, @@ -61,7 +40,7 @@ func newTreeNode(left, right common.Hash) treeNode { func newTree(db *sql.DB) *Tree { t := &Tree{ db: db, - zeroHashes: generateZeroHashes(DefaultHeight), + zeroHashes: generateZeroHashes(types.DefaultHeight), } return t @@ -74,8 +53,8 @@ func (t *Tree) getSiblings(tx *sql.Tx, index uint32, root common.Hash) ( ) { currentNodeHash := root // It starts in height-1 because 0 is the level of the leafs - for h := int(DefaultHeight - 1); h >= 0; h-- { - var currentNode *treeNode + for h := int(types.DefaultHeight - 1); h >= 0; h-- { + var currentNode *types.TreeNode currentNode, err = t.getRHTNode(tx, currentNodeHash) if err != nil { if err == ErrNotFound { @@ -125,24 +104,24 @@ func (t *Tree) getSiblings(tx *sql.Tx, index uint32, root common.Hash) ( } // GetProof returns the merkle proof for a given index and root. -func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) ([DefaultHeight]common.Hash, error) { +func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) ([types.DefaultHeight]common.Hash, error) { tx, err := t.db.BeginTx(ctx, nil) if err != nil { - return [DefaultHeight]common.Hash{}, err + return [types.DefaultHeight]common.Hash{}, err } defer tx.Rollback() siblings, isErrNotFound, err := t.getSiblings(tx, index, root) if err != nil { - return [DefaultHeight]common.Hash{}, err + return [types.DefaultHeight]common.Hash{}, err } if isErrNotFound { - return [DefaultHeight]common.Hash{}, ErrNotFound + return [types.DefaultHeight]common.Hash{}, ErrNotFound } return siblings, nil } -func (t *Tree) getRHTNode(tx *sql.Tx, nodeHash common.Hash) (*treeNode, error) { - node := &treeNode{} +func (t *Tree) getRHTNode(tx *sql.Tx, nodeHash common.Hash) (*types.TreeNode, error) { + node := &types.TreeNode{} err := meddler.QueryRow(tx, node, `select * from rht where hash = $1`, nodeHash) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -170,31 +149,38 @@ func generateZeroHashes(height uint8) []common.Hash { return zeroHashes } -func (t *Tree) storeNodes(tx *sql.Tx, nodes []treeNode) error { +func (t *Tree) storeNodes(tx *sql.Tx, nodes []types.TreeNode) error { for _, node := range nodes { if err := meddler.Insert(tx, "rht", &node); err != nil { + if sqliteErr, ok := db.SQLiteErr(err); ok { + if sqliteErr.Code() == sqlite3.SQLITE_CONSTRAINT_PRIMARYKEY { + // ignore repeated entries. This is likely to happen due to not + // cleaning RHT when reorg + continue + } + } return err } } return nil } -func (t *Tree) storeRoot(tx *sql.Tx, root Root) error { +func (t *Tree) storeRoot(tx *sql.Tx, root types.Root) error { return meddler.Insert(tx, "root", &root) } // GetLastRoot returns the last processed root -func (t *Tree) GetLastRoot(ctx context.Context) (Root, error) { +func (t *Tree) GetLastRoot(ctx context.Context) (types.Root, error) { tx, err := t.db.BeginTx(ctx, nil) if err != nil { - return Root{}, err + return types.Root{}, err } defer tx.Rollback() return t.getLastRootWithTx(tx) } -func (t *Tree) getLastRootWithTx(tx *sql.Tx) (Root, error) { - var root Root +func (t *Tree) getLastRootWithTx(tx *sql.Tx) (types.Root, error) { + var root types.Root err := meddler.QueryRow(tx, &root, `SELECT * FROM root ORDER BY block_num DESC, block_position DESC LIMIT 1;`) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -206,14 +192,14 @@ func (t *Tree) getLastRootWithTx(tx *sql.Tx) (Root, error) { } // GetRootByIndex returns the root associated to the index -func (t *Tree) GetRootByIndex(ctx context.Context, index uint32) (Root, error) { +func (t *Tree) GetRootByIndex(ctx context.Context, index uint32) (types.Root, error) { tx, err := t.db.BeginTx(ctx, nil) if err != nil { - return Root{}, err + return types.Root{}, err } defer tx.Rollback() - var root Root + var root types.Root err = meddler.QueryRow(tx, &root, `SELECT * FROM root WHERE position = $1;`, index) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -225,14 +211,14 @@ func (t *Tree) GetRootByIndex(ctx context.Context, index uint32) (Root, error) { } // GetRootByHash returns the root associated to the hash -func (t *Tree) GetRootByHash(ctx context.Context, hash common.Hash) (Root, error) { +func (t *Tree) GetRootByHash(ctx context.Context, hash common.Hash) (types.Root, error) { tx, err := t.db.BeginTx(ctx, nil) if err != nil { - return Root{}, err + return types.Root{}, err } defer tx.Rollback() - var root Root + var root types.Root err = meddler.QueryRow(tx, &root, `SELECT * FROM root WHERE hash = $1;`, hash) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -251,7 +237,7 @@ func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (com defer tx.Rollback() currentNodeHash := root - for h := int(DefaultHeight - 1); h >= 0; h-- { + for h := int(types.DefaultHeight - 1); h >= 0; h-- { currentNode, err := t.getRHTNode(tx, currentNodeHash) if err != nil { return common.Hash{}, err diff --git a/tree/tree_test.go b/tree/tree_test.go index 1e7fb249..702ee13d 100644 --- a/tree/tree_test.go +++ b/tree/tree_test.go @@ -1,4 +1,4 @@ -package tree +package tree_test import ( "context" @@ -10,8 +10,10 @@ import ( "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/log" + "github.com/0xPolygon/cdk/tree" "github.com/0xPolygon/cdk/tree/migrations" "github.com/0xPolygon/cdk/tree/testvectors" + "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) @@ -33,13 +35,13 @@ func TestMTAddLeaf(t *testing.T) { require.NoError(t, err) db, err := db.NewSQLiteDB(dbPath) require.NoError(t, err) - tree := NewAppendOnlyTree(db) + merkletree := tree.NewAppendOnlyTree(db) // Add exisiting leaves tx, err := db.BeginTx(ctx, nil) require.NoError(t, err) for i, leaf := range testVector.ExistingLeaves { - err = tree.AddLeaf(tx, uint64(i), 0, Leaf{ + err = merkletree.AddLeaf(tx, uint64(i), 0, types.Leaf{ Index: uint32(i), Hash: common.HexToHash(leaf), }) @@ -47,7 +49,7 @@ func TestMTAddLeaf(t *testing.T) { } require.NoError(t, tx.Commit()) if len(testVector.ExistingLeaves) > 0 { - root, err := tree.GetLastRoot(ctx) + root, err := merkletree.GetLastRoot(ctx) require.NoError(t, err) require.Equal(t, common.HexToHash(testVector.CurrentRoot), root.Hash) } @@ -55,14 +57,14 @@ func TestMTAddLeaf(t *testing.T) { // Add new bridge tx, err = db.BeginTx(ctx, nil) require.NoError(t, err) - err = tree.AddLeaf(tx, uint64(len(testVector.ExistingLeaves)), 0, Leaf{ + err = merkletree.AddLeaf(tx, uint64(len(testVector.ExistingLeaves)), 0, types.Leaf{ Index: uint32(len(testVector.ExistingLeaves)), Hash: common.HexToHash(testVector.NewLeaf.CurrentHash), }) require.NoError(t, err) require.NoError(t, tx.Commit()) - root, err := tree.GetLastRoot(ctx) + root, err := merkletree.GetLastRoot(ctx) require.NoError(t, err) require.Equal(t, common.HexToHash(testVector.NewRoot), root.Hash) }) @@ -85,12 +87,12 @@ func TestMTGetProof(t *testing.T) { require.NoError(t, err) db, err := db.NewSQLiteDB(dbPath) require.NoError(t, err) - tree := NewAppendOnlyTree(db) + tre := tree.NewAppendOnlyTree(db) tx, err := db.BeginTx(ctx, nil) require.NoError(t, err) for li, leaf := range testVector.Deposits { - err = tree.AddLeaf(tx, uint64(li), 0, Leaf{ + err = tre.AddLeaf(tx, uint64(li), 0, types.Leaf{ Index: uint32(li), Hash: leaf.Hash(), }) @@ -98,12 +100,12 @@ func TestMTGetProof(t *testing.T) { } require.NoError(t, tx.Commit()) - root, err := tree.GetLastRoot(ctx) + root, err := tre.GetLastRoot(ctx) require.NoError(t, err) expectedRoot := common.HexToHash(testVector.ExpectedRoot) require.Equal(t, expectedRoot, root.Hash) - proof, err := tree.GetProof(ctx, testVector.Index, expectedRoot) + proof, err := tre.GetProof(ctx, testVector.Index, expectedRoot) require.NoError(t, err) for i, sibling := range testVector.MerkleProof { require.Equal(t, common.HexToHash(sibling), proof[i]) diff --git a/tree/types/types.go b/tree/types/types.go new file mode 100644 index 00000000..09a06ba3 --- /dev/null +++ b/tree/types/types.go @@ -0,0 +1,27 @@ +package types + +import "github.com/ethereum/go-ethereum/common" + +const ( + DefaultHeight uint8 = 32 +) + +type Leaf struct { + Index uint32 + Hash common.Hash +} + +type Root struct { + Hash common.Hash `meddler:"hash"` + Index uint32 `meddler:"position"` + BlockNum uint64 `meddler:"block_num"` + BlockPosition uint64 `meddler:"block_position"` +} + +type TreeNode struct { + Hash common.Hash `meddler:"hash"` + Left common.Hash `meddler:"left"` + Right common.Hash `meddler:"right"` +} + +type Proof [DefaultHeight]common.Hash diff --git a/tree/updatabletree.go b/tree/updatabletree.go index bae067ba..b13970f2 100644 --- a/tree/updatabletree.go +++ b/tree/updatabletree.go @@ -2,6 +2,8 @@ package tree import ( "database/sql" + + "github.com/0xPolygon/cdk/tree/types" ) // UpdatableTree is a tree that have updatable leaves, and doesn't need to have sequential inserts @@ -18,7 +20,7 @@ func NewUpdatableTree(db *sql.DB) (*UpdatableTree, error) { return ut, nil } -func (t *UpdatableTree) UpsertLeaf(tx *sql.Tx, blockNum, blockPosition uint64, leaf Leaf) error { +func (t *UpdatableTree) UpsertLeaf(tx *sql.Tx, blockNum, blockPosition uint64, leaf types.Leaf) error { root, err := t.getLastRootWithTx(tx) if err != nil { return err @@ -28,9 +30,9 @@ func (t *UpdatableTree) UpsertLeaf(tx *sql.Tx, blockNum, blockPosition uint64, l return err } currentChildHash := leaf.Hash - newNodes := []treeNode{} - for h := uint8(0); h < DefaultHeight; h++ { - var parent treeNode + newNodes := []types.TreeNode{} + for h := uint8(0); h < types.DefaultHeight; h++ { + var parent types.TreeNode if leaf.Index&(1< 0 { // Add child to the right parent = newTreeNode(siblings[h], currentChildHash) @@ -41,7 +43,7 @@ func (t *UpdatableTree) UpsertLeaf(tx *sql.Tx, blockNum, blockPosition uint64, l currentChildHash = parent.Hash newNodes = append(newNodes, parent) } - if err := t.storeRoot(tx, Root{ + if err := t.storeRoot(tx, types.Root{ Hash: currentChildHash, Index: leaf.Index, BlockNum: blockNum, From 37cf940c6b4a071d56cb133a609d7270fe5be252 Mon Sep 17 00:00:00 2001 From: Arnau Date: Wed, 4 Sep 2024 11:57:39 +0200 Subject: [PATCH 13/31] bridgesync working with sqlite --- bridgesync/migrations/bridgesync0001.sql | 6 +++--- bridgesync/processor.go | 4 ++-- bridgesync/processor_test.go | 11 ++++++----- db/sqlite.go | 7 ++++++- tmp.sqlite | Bin 61440 -> 0 bytes 5 files changed, 17 insertions(+), 11 deletions(-) delete mode 100644 tmp.sqlite diff --git a/bridgesync/migrations/bridgesync0001.sql b/bridgesync/migrations/bridgesync0001.sql index 9f544917..b86d9243 100644 --- a/bridgesync/migrations/bridgesync0001.sql +++ b/bridgesync/migrations/bridgesync0001.sql @@ -9,7 +9,7 @@ CREATE TABLE block ( ); CREATE TABLE bridge ( - block_num INTEGER NOT NULL REFERENCES block (num) ON DELETE CASCADE, + block_num INTEGER NOT NULL REFERENCES block(num) ON DELETE CASCADE, block_pos INTEGER NOT NULL, leaf_type INTEGER NOT NULL, origin_network INTEGER NOT NULL, @@ -23,8 +23,8 @@ CREATE TABLE bridge ( ); CREATE TABLE claim ( - block_num BIGINT NOT NULL REFERENCES block (block_num) ON DELETE CASCADE, - block_pos BIGINT NOT NULL, + block_num INTEGER NOT NULL REFERENCES block(num) ON DELETE CASCADE, + block_pos INTEGER NOT NULL, global_index DECIMAL(78, 0) NOT NULL, origin_network INTEGER NOT NULL, origin_address VARCHAR NOT NULL, diff --git a/bridgesync/processor.go b/bridgesync/processor.go index 0ca42701..46a19ba5 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -124,7 +124,7 @@ func (p *processor) GetBridges( return nil, err } - bridges := []Bridge{} + bridges := []*Bridge{} err = meddler.QueryAll(tx, &bridges, ` SELECT * FROM bridge WHERE block_num >= $1 AND block_num <= $2; @@ -132,7 +132,7 @@ func (p *processor) GetBridges( if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } - return bridges, err + return db.SlicePtrsToSlice(bridges).([]Bridge), err } func (p *processor) GetClaims( diff --git a/bridgesync/processor_test.go b/bridgesync/processor_test.go index 7aaee223..db917e8d 100644 --- a/bridgesync/processor_test.go +++ b/bridgesync/processor_test.go @@ -19,8 +19,9 @@ import ( ) func TestProceessor(t *testing.T) { - path := path.Join("/Users/arnaub/Documents/polygon/cdk", "tmp.sqlite") - // path := path.Join(t.TempDir(), "tmp.sqlite") + // /var/folders/mg/0s7xy6zx5fl70c15csg0jxx00000gp/T/TestProceessor817662394/001/tmp.sqlite + path := path.Join(t.TempDir(), "tmp.sqlite") + log.Debugf("sqlite path: %s", path) err := migrationsBridge.RunMigrations(path) require.NoError(t, err) p, err := newProcessor(path, "foo") @@ -213,7 +214,7 @@ func TestProceessor(t *testing.T) { p: p, description: "after block3 reorged", ctx: context.Background(), - expectedLastProcessedBlock: 2, + expectedLastProcessedBlock: 1, expectedErr: nil, }, &reorgAction{ @@ -299,7 +300,7 @@ func TestProceessor(t *testing.T) { for _, a := range actions { log.Debugf("%s: %s", a.method(), a.desc()) - t.Run(fmt.Sprintf("%s: %s", a.method(), a.desc()), a.execute) + a.execute(t) } } @@ -357,7 +358,7 @@ var ( OriginAddress: common.HexToAddress("03"), DestinationNetwork: 3, DestinationAddress: common.HexToAddress("03"), - Amount: nil, + Amount: big.NewInt(0), Metadata: common.Hex2Bytes("03"), DepositCount: 2, }}, diff --git a/db/sqlite.go b/db/sqlite.go index d3417d58..76976b7e 100644 --- a/db/sqlite.go +++ b/db/sqlite.go @@ -9,5 +9,10 @@ import ( // NewSQLiteDB creates a new SQLite DB func NewSQLiteDB(dbPath string) (*sql.DB, error) { initMeddler() - return sql.Open("sqlite", dbPath) + db, err := sql.Open("sqlite", dbPath) + if err != nil { + return nil, err + } + _, err = db.Exec(`PRAGMA foreign_keys = ON`) + return db, err } diff --git a/tmp.sqlite b/tmp.sqlite deleted file mode 100644 index 5460eb72287cc80dd0459d6dc89be8bd0794e795..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61440 zcmeI53tUWF`^RURnr5cCh|QVzK!$1RSW+#({E2<0G0^51KcMkn_B|NP(g^Z6g1WoGX^d;j+Hto2>bTFpFr z>=`@8TdtO2Q98LN00AHX1b_e#XeN+EW9#!f zbf6|hs-;sDGF6zGcyNaJi9G#9n7`*>ZxKf9z(lBIds@|3yGnnnbF?x>u9hpK zkjTr&Uo>3ghc(v>3-Iw86Ci4;{uG5WBtjAu8%YQUdkrVFA9dOSEqkq0EE{VBI={cs zXWL2CT;hmY#I|OU3WZ2$FmIB+KA+F0E;7;}2~kMpk(veL6DXQpAE;=z12ww2w5l!U zCmJU56Zs4gjm0#lU_C#cX@iM+@BPCc0^=ga{p?rLq}vwFGq=amEMZ zg!?9iN~uu9Mr%u26p>PS6wzkwgBtfOioc(&5ome&09(5Xt!!vx&?ejl+(?;Pic8hf zCMPY+!QSG*M2qAxl1Ku&G*s4d2yG1(i@imjK25!^H4wET%dRQbBt!_=uxxA?biO

GMrZsq>YZfiOiS$3taJOZq26p=sY2#zO1%wlNThN#K7q1X`PH zBA}2-r%KfE(b|;$u56BE?JoJ-MD>|~ZzF=+>g6_^YRj6(L>t!H8V{cz3vGqXhmgT# znt4+aqBXw$UM&}-QY5wlEGtU`fBtK^YVRXi3Ui?_opq|wm|xeS*`)fN~r zf@NxXq|C-$ht3~k`#D^#yh((ucF>6T5)AZyff z00e*l5C8%|00{ht2@KSsb&gf5WHNz3=qPY>vKP483!E^a&`sd%CJ;EdIJ@=}3Nc%O zqdf00e*l5C8%|00;m9AOHmZsRRsYov9!43_6B1Yvw0819bhL z_|iXx*YHnm9@HBM00AHX1b_e#00KY&2mk>f00e*l5cm=S9jXo!UH^yA|6ig6$AAD3 z00KY&2mk>f00e*l5C8%|00{iE3D9UvCc6Gl<(;7r4=6wY2mk>f00e*l5C8%|00;m9 zAOHk_!2f#!PE-RXgUNIv{&6+8_G?w+wrf00e*l5C8%|;OinlT>o$S|Nol%|6TjK8V9Wb0zd!=00AHX1b_e#00KY& z2mk>f@J$e~qUw1wm<;Kf00e*l5cui{Skk$cH1b_e#00KY& z2mk>f00e*l5C8%|fFMAlHQoOYqj^wx>v&Gw5^fk*hqHmxmwk~P&ek>9XyC%S#8R;6 z%*{+U#$`qngQ1_LKY(6FkEXNqw(1Sky{fCyWz&8n3_t+_-yi`T(k?m-G9qbF?k>@kl#Q!4@^={DK4KiU#3&-D zb~1DEltjw7?YKGeLS}_^Rn{)IN4NeNUT2hVbIxYbW|!Ip&69__O|p8k`b3CurDdXT zLG05J5^sy0b+0`=3@XyXH=L@Nb*3uL!dQ0288<^-$gJEPafp_~TKI}$Jl28!OPy7t z@%H3P>dBX!(iH+mdhcqNh5NWxF~3jyDT(pmhh*;BI)y>X&x?AG+?t+tC~3(S3%o1x zLS`k#*G6P_W75@A0m0_y_a4YOf2;a;o2ZWb%h94k2i-!qOm(<-)Bei7U!&utd+!e` z(v6ds9|#n4(x!8E|7+HFj~(zX$P1a3BS(HL{VDi_AKkFw*00gm%ywkU_sB45LC(nE5|fI|@Xp8!nU%(K9d^ft zzT>_vwu+t*_h_ASoZ0!z$$bm!Mi-fwB+p-a@Vr`A`J&(RZH0DAXm@zHok?nZ+O#?0 zdmk>iR`qoLMZ6R8LS`j@_(S=`xUEGGhUtGlK~{8c>zh+EDUHuf#L7SejA}B9RXFjq zI{z16e6Htm4UuiX^srq6H_ zjn;<#(H=w>Ts)YUb#AvBxfUvdzUZ`o^H8 zuG@}hgeEXcLmOu5-Tl>td*2V|BQIoD96f`7WS@zi) z7;C-d0*i?ojLRuy&rI@Gx+&9&gU$v_o#rxK`CYZ4VRZTY^t;n>W8{U*%1-m#pwvfZ zQgQc}3!a`IQg1b-;@nx4Y?R_h6LoNP;nhDq=Pjsl&Jrzt|JXI(y+>_Yuf6@t@9(Nw zGBd+@wE8MtSofFeA#PHlBkJCBgPTQvxPfi!% z!&47nl{b5pjkwuRIC9pcPHsLI9=sYBy5)IZCEgKvA+u86&@STqbf3!eGcR9!*D3R; z@dk>!fh0h%=#R(Wm1Oj7$PMp#;AMbE{i>m_+;8_=;@-aV?Tz$vKh$)=?gz$|hHu6@ zATMNAbmuz!V0v%V#h1eSCSisuEJ7vXQJy4RynD^;TntBLj{tcA0~4yniSmQI_S zXyd@v+@!I`7_7c|D_;#`r0b z-aEOlGW1UA{@?WXCEW`fP+TSqdNXO=tyIrj4LO#o+G9QLu6>q(w?kgYtk|AnZQ7K- zFo=DaUwzr^mj^k8UWcA;O9(7t*x>1c#y!@3s(5};$Nw_TvK2n8@vR&1`@1*Z%l&KI z;+R>r@7J2+hR6$ zRFeaTdwV*T#4j#S2!3#97)zCLx7exI`1Br^a31nPX65HO)%V-Q9?6w$_hK%M^Hm(r zj^}RBUuM}avZo<~xA;X+=*}y}XI|)7h2N@3*xT_s>%zn6%U)Zye*ZeDY{J7M=Ws6a zLT2Ua&u@-C&B=Q#{^Q_*Gh@nFjHSQqc-NkBwdm92|zE*Tl-J!bjneNh6 zxupT#)iKv>c?oZ#bfy(AuRMfvkQXv5vpZz19#^8K_c5)ZihKOQEYz_qs?LADZ}8X~ z<^y(^RXHsyE_p0sJtC4JGd2IvEMqbFQbRQpb=}}q7 zY~cvC6K%u>C;UuGwW^`fh(9aBz2Y~4N&Q|ougc_C%oF^d`n*kB6WMM|;`pxZyJg8P zO?*A$N&O1k0C^#^qJGhD|DN@JHxCZWm^Z+8>+Q|r4oUIO-&dGl5l-Lf8tne2eBkWc z#ZbnTkVv^0I0E_QIpJ9Z))XCW_SRy@l)UB6U=`JBuNT>X0d-pbg` z_M_KWWRDKNKK}a+&dczUzb;oXj;_t$cIRs2-i&~^ItA&mfxa`QG3BL0dA|O)aVGLY zW<~$_oA% z>Z0-cE7bA#=7co#Ih~-#n~m%ADZ~}0(^hvc&bPhbwqH3H*GFE+tQ0a{oW7LLJ@T(h z%-ThIkFrwx9a|EVl;7U@%!)_t!+!`~kZ5suzHh0A@s0sg_rEu^-*GeM)t-(I4ELMO zvDm%NGz_OBFJxApG){W9K5KWZQ~yH#R`W`hG1WZs@W${fb=gnm)1&I zWnZp19dB)K&g^h*(^P-XtT}o~?U;8i*yDQ03z?NOE_RdcBzCJhrvKFI?!YS76^oV^ z8QB+ds?kz;-UFR?ETe9%ysx41{<%AvR}@qG-!umj{~<(RtUTA zF1RrwXnppUyRHj$^9ttSG~|WMir%vMr%pVImc*A@&cGM;Nm($mV;=R#L+j#wKjh^Lk@) zE2mJr=p6#Nf6PEi z;e_(?xYrDR;Wl!^IeXcq>|NYk-UntB?ozIZSI+*P^OjxDDdQ|=)AOHk_01yBIKmZ5;fp3C9cbYeq?D7DHL}b~0b0i{5&YK|- zS#G^65|O3GyC4x+X1g;IktL=(ArV<#*%XP$(!wT4M3&X%BN16r))q_|nFI{nrS-3wS_rgkL0kZf76L6>Urk)VZv=hp)UT#bp&=jp j6#lTcpa2%YLW@AlCd?PWqJ==q)_))_zKOJCb0hx;CX{X( From 3083e5c53525c1aa6e05bcb7cfec5a6448d539d2 Mon Sep 17 00:00:00 2001 From: Arnau Date: Wed, 4 Sep 2024 16:45:14 +0200 Subject: [PATCH 14/31] pass tests --- bridgesync/e2e_test.go | 6 +- bridgesync/migrations/bridgesync0001_test.go | 4 +- bridgesync/migrations/migrations.go | 4 +- bridgesync/processor.go | 23 +- bridgesync/processor_test.go | 1 - claimsponsor/e2e_test.go | 3 +- db/meddler.go | 27 ++ db/sqlite.go | 7 +- l1bridge2infoindexsync/e2e_test.go | 11 +- l1infotreesync/downloader.go | 23 +- l1infotreesync/e2e_test.go | 15 +- l1infotreesync/l1infotreesync.go | 6 +- .../migrations/l1infotreesync0001.sql | 22 + l1infotreesync/migrations/migrations.go | 45 ++ l1infotreesync/processor.go | 448 ++++++------------ sync/evmdriver.go | 2 +- test/helpers/aggoracle_e2e.go | 3 +- tree/appendonlytree.go | 9 +- tree/migrations/migrations.go | 15 +- tree/migrations/tree0001.sql | 10 +- tree/tree.go | 58 ++- tree/tree_test.go | 4 +- tree/types/types.go | 8 +- tree/updatabletree.go | 18 +- 24 files changed, 380 insertions(+), 392 deletions(-) create mode 100644 l1infotreesync/migrations/l1infotreesync0001.sql create mode 100644 l1infotreesync/migrations/migrations.go diff --git a/bridgesync/e2e_test.go b/bridgesync/e2e_test.go index b61c4ca3..f3f64969 100644 --- a/bridgesync/e2e_test.go +++ b/bridgesync/e2e_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math/big" + "path" "testing" "time" @@ -45,7 +46,7 @@ func newSimulatedClient(t *testing.T, auth *bind.TransactOpts) ( func TestBridgeEventE2E(t *testing.T) { ctx := context.Background() - dbPathSyncer := t.TempDir() + dbPathSyncer := path.Join(t.TempDir(), "tmp.sqlite") dbPathReorg := t.TempDir() privateKey, err := crypto.GenerateKey() require.NoError(t, err) @@ -65,11 +66,12 @@ func TestBridgeEventE2E(t *testing.T) { expectedBridges := []bridgesync.Bridge{} for i := 0; i < 100; i++ { bridge := bridgesync.Bridge{ + BlockNum: uint64(2 + i), Amount: big.NewInt(0), DepositCount: uint32(i), DestinationNetwork: 3, DestinationAddress: common.HexToAddress("f00"), - Metadata: []byte{}, + Metadata: nil, } tx, err := bridgeSc.BridgeAsset( auth, diff --git a/bridgesync/migrations/bridgesync0001_test.go b/bridgesync/migrations/bridgesync0001_test.go index ccf1640c..10355e37 100644 --- a/bridgesync/migrations/bridgesync0001_test.go +++ b/bridgesync/migrations/bridgesync0001_test.go @@ -24,7 +24,7 @@ func Test001(t *testing.T) { _, err = tx.Exec(` INSERT INTO block (num) VALUES (1); - INSERT INTO claim ( + INSERT INTO bridge ( block_num, block_pos, leaf_type, @@ -37,7 +37,7 @@ func Test001(t *testing.T) { deposit_count ) VALUES (1, 0, 0, 0, '0x0000', 0, '0x0000', 0, NULL, 0); - INSERT INTO bridge ( + INSERT INTO claim ( block_num, block_pos, global_index, diff --git a/bridgesync/migrations/migrations.go b/bridgesync/migrations/migrations.go index 8050d422..b0c611d8 100644 --- a/bridgesync/migrations/migrations.go +++ b/bridgesync/migrations/migrations.go @@ -27,9 +27,9 @@ var bridgeMigrations = &migrate.MemoryMigrationSource{ } func RunMigrations(dbPath string) error { - bridgeMigrations.Migrations = append( + migs := append( bridgeMigrations.Migrations, treeMigrations.Migrations.Migrations..., ) - return db.RunMigrations(dbPath, bridgeMigrations) + return db.RunMigrations(dbPath, &migrate.MemoryMigrationSource{Migrations: migs}) } diff --git a/bridgesync/processor.go b/bridgesync/processor.go index 46a19ba5..5de3359e 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -7,6 +7,7 @@ import ( "errors" "math/big" + "github.com/0xPolygon/cdk/bridgesync/migrations" "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/log" "github.com/0xPolygon/cdk/sync" @@ -75,9 +76,9 @@ type Claim struct { Amount *big.Int `meddler:"amount,bigint"` ProofLocalExitRoot types.Proof `meddler:"proof_local_exit_root,merkleproof"` ProofRollupExitRoot types.Proof `meddler:"proof_rollup_exit_root,merkleproof"` - MainnetExitRoot common.Hash `meddler:"mainnet_exit_root"` - RollupExitRoot common.Hash `meddler:"rollup_exit_root"` - GlobalExitRoot common.Hash `meddler:"global_exit_root"` + MainnetExitRoot common.Hash `meddler:"mainnet_exit_root,hash"` + RollupExitRoot common.Hash `meddler:"rollup_exit_root,hash"` + GlobalExitRoot common.Hash `meddler:"global_exit_root,hash"` DestinationNetwork uint32 `meddler:"destination_network"` Metadata []byte `meddler:"metadata"` IsMessage bool `meddler:"is_message"` @@ -96,13 +97,17 @@ type processor struct { log *log.Logger } -func newProcessor(dbPath, dbPrefix string) (*processor, error) { +func newProcessor(dbPath, loggerPrefix string) (*processor, error) { + err := migrations.RunMigrations(dbPath) + if err != nil { + return nil, err + } db, err := db.NewSQLiteDB(dbPath) if err != nil { return nil, err } - logger := log.WithFields("bridge-syncer", dbPrefix) - exitTree := tree.NewAppendOnlyTree(db) + logger := log.WithFields("bridge-syncer", loggerPrefix) + exitTree := tree.NewAppendOnlyTree(db, "") return &processor{ db: db, exitTree: exitTree, @@ -113,7 +118,7 @@ func newProcessor(dbPath, dbPrefix string) (*processor, error) { func (p *processor) GetBridges( ctx context.Context, fromBlock, toBlock uint64, ) ([]Bridge, error) { - tx, err := p.db.BeginTx(ctx, nil) + tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return nil, err } @@ -138,7 +143,7 @@ func (p *processor) GetBridges( func (p *processor) GetClaims( ctx context.Context, fromBlock, toBlock uint64, ) ([]Claim, error) { - tx, err := p.db.BeginTx(ctx, nil) + tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return nil, err } @@ -174,7 +179,7 @@ func (p *processor) isBlockProcessed(tx *sql.Tx, blockNum uint64) error { // GetLastProcessedBlock returns the last processed block by the processor, including blocks // that don't have events func (p *processor) GetLastProcessedBlock(ctx context.Context) (uint64, error) { - tx, err := p.db.BeginTx(ctx, nil) + tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return 0, err } diff --git a/bridgesync/processor_test.go b/bridgesync/processor_test.go index db917e8d..9bcdc628 100644 --- a/bridgesync/processor_test.go +++ b/bridgesync/processor_test.go @@ -19,7 +19,6 @@ import ( ) func TestProceessor(t *testing.T) { - // /var/folders/mg/0s7xy6zx5fl70c15csg0jxx00000gp/T/TestProceessor817662394/001/tmp.sqlite path := path.Join(t.TempDir(), "tmp.sqlite") log.Debugf("sqlite path: %s", path) err := migrationsBridge.RunMigrations(path) diff --git a/claimsponsor/e2e_test.go b/claimsponsor/e2e_test.go index 796a09ba..433755b4 100644 --- a/claimsponsor/e2e_test.go +++ b/claimsponsor/e2e_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math/big" + "path" "testing" "time" @@ -21,7 +22,7 @@ func TestE2EL1toEVML2(t *testing.T) { // start other needed components ctx := context.Background() env := helpers.SetupAggoracleWithEVMChain(t) - dbPathBridgeSyncL1 := t.TempDir() + dbPathBridgeSyncL1 := path.Join(t.TempDir(), "tmp.sqlite") testClient := helpers.TestClient{ClientRenamed: env.L1Client.Client()} bridgeSyncL1, err := bridgesync.NewL1(ctx, dbPathBridgeSyncL1, env.BridgeL1Addr, 10, etherman.LatestBlock, env.ReorgDetector, testClient, 0, time.Millisecond*10, 0, 0) require.NoError(t, err) diff --git a/db/meddler.go b/db/meddler.go index a2ef9dbd..aa5f992c 100644 --- a/db/meddler.go +++ b/db/meddler.go @@ -17,6 +17,7 @@ func initMeddler() { meddler.Default = meddler.SQLite meddler.Register("bigint", BigIntMeddler{}) meddler.Register("merkleproof", MerkleProofMeddler{}) + meddler.Register("hash", HashMeddler{}) } func SQLiteErr(err error) (*sqlite.Error, bool) { @@ -122,3 +123,29 @@ func (b MerkleProofMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{ s = strings.TrimSuffix(s, ",") return s, nil } + +// HashMeddler encodes or decodes the field value to or from JSON +type HashMeddler struct{} + +// PreRead is called before a Scan operation for fields that have the ProofMeddler +func (b HashMeddler) PreRead(fieldAddr interface{}) (scanTarget interface{}, err error) { + // give a pointer to a byte buffer to grab the raw data + return new(string), nil +} + +// PostRead is called after a Scan operation for fields that have the ProofMeddler +func (b HashMeddler) PostRead(fieldPtr, scanTarget interface{}) error { + ptr := scanTarget.(*string) + if ptr == nil { + return fmt.Errorf("HashMeddler.PostRead: nil pointer") + } + field := fieldPtr.(*common.Hash) + *field = common.HexToHash(*ptr) + return nil +} + +// PreWrite is called before an Insert or Update operation for fields that have the ProofMeddler +func (b HashMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) { + field := fieldPtr.(common.Hash) + return field.Hex(), nil +} diff --git a/db/sqlite.go b/db/sqlite.go index 76976b7e..85a86430 100644 --- a/db/sqlite.go +++ b/db/sqlite.go @@ -13,6 +13,11 @@ func NewSQLiteDB(dbPath string) (*sql.DB, error) { if err != nil { return nil, err } - _, err = db.Exec(`PRAGMA foreign_keys = ON`) + _, err = db.Exec(` + PRAGMA foreign_keys = ON; + pragma journal_mode = WAL; + pragma synchronous = normal; + pragma journal_size_limit = 6144000; + `) return db, err } diff --git a/l1bridge2infoindexsync/e2e_test.go b/l1bridge2infoindexsync/e2e_test.go index 2aa8e38f..601385c8 100644 --- a/l1bridge2infoindexsync/e2e_test.go +++ b/l1bridge2infoindexsync/e2e_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math/big" + "path" "strconv" "testing" "time" @@ -100,6 +101,7 @@ func newSimulatedClient(authDeployer, authCaller *bind.TransactOpts) ( } if precalculatedAddr != checkGERAddr { err = errors.New("error deploying bridge") + return } gerAddr, _, gerContract, err = polygonzkevmglobalexitrootv2.DeployPolygonzkevmglobalexitrootv2( @@ -118,8 +120,8 @@ func newSimulatedClient(authDeployer, authCaller *bind.TransactOpts) ( func TestE2E(t *testing.T) { ctx := context.Background() - dbPathBridgeSync := t.TempDir() - dbPathL1Sync := t.TempDir() + dbPathBridgeSync := path.Join(t.TempDir(), "tmp.sqlite") + dbPathL1Sync := path.Join(t.TempDir(), "tmp.sqlite") dbPathReorg := t.TempDir() dbPathL12InfoSync := t.TempDir() @@ -186,6 +188,7 @@ func TestE2E(t *testing.T) { // Wait for block to be finalised updateAtBlock, err := client.Client().BlockNumber(ctx) + require.NoError(t, err) for { lastFinalisedBlock, err := client.Client().BlockByNumber(ctx, big.NewInt(int64(rpc.FinalizedBlockNumber))) require.NoError(t, err) @@ -199,11 +202,11 @@ func TestE2E(t *testing.T) { // Wait for syncer to catch up syncerUpToDate := false var errMsg string + lb, err := client.Client().BlockByNumber(ctx, big.NewInt(int64(rpc.FinalizedBlockNumber))) + require.NoError(t, err) for i := 0; i < 10; i++ { lpb, err := bridge2InfoSync.GetLastProcessedBlock(ctx) require.NoError(t, err) - lb, err := client.Client().BlockByNumber(ctx, big.NewInt(int64(rpc.FinalizedBlockNumber))) - require.NoError(t, err) if lpb == lb.NumberU64() { syncerUpToDate = true break diff --git a/l1infotreesync/downloader.go b/l1infotreesync/downloader.go index bc4305bc..8e5cbb98 100644 --- a/l1infotreesync/downloader.go +++ b/l1infotreesync/downloader.go @@ -62,6 +62,7 @@ func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Addr ) } b.Events = append(b.Events, Event{UpdateL1InfoTree: &UpdateL1InfoTree{ + BlockPosition: uint64(l.Index), MainnetExitRoot: l1InfoTreeUpdate.MainnetExitRoot, RollupExitRoot: l1InfoTreeUpdate.RollupExitRoot, ParentHash: b.ParentHash, @@ -91,11 +92,12 @@ func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Addr ) } b.Events = append(b.Events, Event{VerifyBatches: &VerifyBatches{ - RollupID: verifyBatches.RollupID, - NumBatch: verifyBatches.NumBatch, - StateRoot: verifyBatches.StateRoot, - ExitRoot: verifyBatches.ExitRoot, - Aggregator: verifyBatches.Aggregator, + BlockPosition: uint64(l.Index), + RollupID: verifyBatches.RollupID, + NumBatch: verifyBatches.NumBatch, + StateRoot: verifyBatches.StateRoot, + ExitRoot: verifyBatches.ExitRoot, + Aggregator: verifyBatches.Aggregator, }}) return nil } @@ -108,11 +110,12 @@ func buildAppender(client EthClienter, globalExitRoot, rollupManager common.Addr ) } b.Events = append(b.Events, Event{VerifyBatches: &VerifyBatches{ - RollupID: verifyBatches.RollupID, - NumBatch: verifyBatches.NumBatch, - StateRoot: verifyBatches.StateRoot, - ExitRoot: verifyBatches.ExitRoot, - Aggregator: verifyBatches.Aggregator, + BlockPosition: uint64(l.Index), + RollupID: verifyBatches.RollupID, + NumBatch: verifyBatches.NumBatch, + StateRoot: verifyBatches.StateRoot, + ExitRoot: verifyBatches.ExitRoot, + Aggregator: verifyBatches.Aggregator, }}) return nil } diff --git a/l1infotreesync/e2e_test.go b/l1infotreesync/e2e_test.go index 60b371c3..5ac6ac21 100644 --- a/l1infotreesync/e2e_test.go +++ b/l1infotreesync/e2e_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math/big" + "path" "strconv" "testing" "time" @@ -68,7 +69,7 @@ func newSimulatedClient(auth *bind.TransactOpts) ( func TestE2E(t *testing.T) { ctx := context.Background() - dbPath := t.TempDir() + dbPath := path.Join(t.TempDir(), "tmp.sqlite") privateKey, err := crypto.GenerateKey() require.NoError(t, err) auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(1337)) @@ -107,7 +108,7 @@ func TestE2E(t *testing.T) { require.Equal(t, g, expectedRoot) actualRoot, err := syncer.GetL1InfoTreeRootByIndex(ctx, uint32(i)) require.NoError(t, err) - require.Equal(t, common.Hash(expectedRoot), actualRoot) + require.Equal(t, common.Hash(expectedRoot), actualRoot.Hash) } // Update 3 rollups (verify batches event) 3 times @@ -128,7 +129,7 @@ func TestE2E(t *testing.T) { require.NoError(t, err) actualRollupExitRoot, err := syncer.GetLastRollupExitRoot(ctx) require.NoError(t, err) - require.Equal(t, common.Hash(expectedRollupExitRoot), actualRollupExitRoot, fmt.Sprintf("rollupID: %d, i: %d", rollupID, i)) + require.Equal(t, common.Hash(expectedRollupExitRoot), actualRollupExitRoot.Hash, fmt.Sprintf("rollupID: %d, i: %d", rollupID, i)) } } } @@ -174,7 +175,7 @@ func TestStressAndReorgs(t *testing.T) { ) ctx := context.Background() - dbPathSyncer := t.TempDir() + dbPathSyncer := path.Join(t.TempDir(), "tmp.sqlite") dbPathReorg := t.TempDir() privateKey, err := crypto.GenerateKey() require.NoError(t, err) @@ -222,11 +223,11 @@ func TestStressAndReorgs(t *testing.T) { syncerUpToDate := false var errMsg string + lb, err := client.Client().BlockNumber(ctx) + require.NoError(t, err) for i := 0; i < 50; i++ { lpb, err := syncer.GetLastProcessedBlock(ctx) require.NoError(t, err) - lb, err := client.Client().BlockNumber(ctx) - require.NoError(t, err) if lpb == lb { syncerUpToDate = true break @@ -241,7 +242,7 @@ func TestStressAndReorgs(t *testing.T) { require.NoError(t, err) actualRollupExitRoot, err := syncer.GetLastRollupExitRoot(ctx) require.NoError(t, err) - require.Equal(t, common.Hash(expectedRollupExitRoot), actualRollupExitRoot) + require.Equal(t, common.Hash(expectedRollupExitRoot), actualRollupExitRoot.Hash) // Assert L1 Info tree root expectedL1InfoRoot, err := gerSc.GetRoot(&bind.CallOpts{Pending: false}) diff --git a/l1infotreesync/l1infotreesync.go b/l1infotreesync/l1infotreesync.go index 360e9d8a..1cfcdd0b 100644 --- a/l1infotreesync/l1infotreesync.go +++ b/l1infotreesync/l1infotreesync.go @@ -37,7 +37,7 @@ func New( retryAfterErrorPeriod time.Duration, maxRetryAttemptsAfterError int, ) (*L1InfoTreeSync, error) { - processor, err := newProcessor(ctx, dbPath) + processor, err := newProcessor(dbPath) if err != nil { return nil, err } @@ -93,12 +93,12 @@ func (s *L1InfoTreeSync) Start(ctx context.Context) { } // GetL1InfoTreeMerkleProof creates a merkle proof for the L1 Info tree -func (s *L1InfoTreeSync) GetL1InfoTreeMerkleProof(ctx context.Context, index uint32) ([32]common.Hash, common.Hash, error) { +func (s *L1InfoTreeSync) GetL1InfoTreeMerkleProof(ctx context.Context, index uint32) (types.Proof, types.Root, error) { return s.processor.GetL1InfoTreeMerkleProof(ctx, index) } // GetRollupExitTreeMerkleProof creates a merkle proof for the rollup exit tree -func (s *L1InfoTreeSync) GetRollupExitTreeMerkleProof(ctx context.Context, networkID uint32, root common.Hash) ([32]common.Hash, error) { +func (s *L1InfoTreeSync) GetRollupExitTreeMerkleProof(ctx context.Context, networkID uint32, root common.Hash) (types.Proof, error) { if networkID == 0 { return tree.EmptyProof, nil } diff --git a/l1infotreesync/migrations/l1infotreesync0001.sql b/l1infotreesync/migrations/l1infotreesync0001.sql new file mode 100644 index 00000000..39a45dd4 --- /dev/null +++ b/l1infotreesync/migrations/l1infotreesync0001.sql @@ -0,0 +1,22 @@ +-- +migrate Down +DROP TABLE IF EXISTS block; +DROP TABLE IF EXISTS claim; +DROP TABLE IF EXISTS bridge; + +-- +migrate Up +CREATE TABLE block ( + num BIGINT PRIMARY KEY +); + +CREATE TABLE l1info_leaf ( + block_num INTEGER NOT NULL REFERENCES block(num) ON DELETE CASCADE, + block_pos INTEGER NOT NULL, + position INTEGER NOT NULL, + previous_block_hash VARCHAR NOT NULL, + timestamp INTEGER NOT NULL, + mainnet_exit_root VARCHAR NOT NULL, + rollup_exit_root VARCHAR NOT NULL, + global_exit_root VARCHAR NOT NULL, + hash VARCHAR NOT NULL, + PRIMARY KEY (block_num, block_pos) +); diff --git a/l1infotreesync/migrations/migrations.go b/l1infotreesync/migrations/migrations.go new file mode 100644 index 00000000..28fb2389 --- /dev/null +++ b/l1infotreesync/migrations/migrations.go @@ -0,0 +1,45 @@ +package migrations + +import ( + "strings" + + "github.com/0xPolygon/cdk/db" + "github.com/0xPolygon/cdk/log" + treeMigrations "github.com/0xPolygon/cdk/tree/migrations" + migrate "github.com/rubenv/sql-migrate" + + _ "embed" +) + +const ( + upDownSeparator = "-- +migrate Up" + RollupExitTreePrefix = "rollup_exit_" + L1InfoTreePrefix = "l1_info_" +) + +//go:embed l1infotreesync0001.sql +var mig001 string +var mig001splitted = strings.Split(mig001, upDownSeparator) + +var Migrations = &migrate.MemoryMigrationSource{ + Migrations: []*migrate.Migration{ + { + Id: "l1infotreesync0001", + Up: []string{mig001splitted[1]}, + Down: []string{mig001splitted[0]}, + }, + }, +} + +func RunMigrations(dbPath string) error { + migs := []*migrate.Migration{} + retMigs := treeMigrations.MigrationsWithPrefix(RollupExitTreePrefix) + migs = append(migs, retMigs...) + l1InfoMigs := treeMigrations.MigrationsWithPrefix(L1InfoTreePrefix) + migs = append(migs, l1InfoMigs...) + migs = append(migs, Migrations.Migrations...) + for _, m := range migs { + log.Debugf("%+v", m.Id) + } + return db.RunMigrations(dbPath, &migrate.MemoryMigrationSource{Migrations: migs}) +} diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index 86943565..f1b33cfe 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -2,56 +2,37 @@ package l1infotreesync import ( "context" + "database/sql" "encoding/binary" - "encoding/json" "errors" - "fmt" - "github.com/0xPolygon/cdk/common" + "github.com/0xPolygon/cdk/db" + "github.com/0xPolygon/cdk/l1infotreesync/migrations" "github.com/0xPolygon/cdk/log" "github.com/0xPolygon/cdk/sync" "github.com/0xPolygon/cdk/tree" treeTypes "github.com/0xPolygon/cdk/tree/types" ethCommon "github.com/ethereum/go-ethereum/common" "github.com/iden3/go-iden3-crypto/keccak256" - "github.com/ledgerwatch/erigon-lib/kv" - "github.com/ledgerwatch/erigon-lib/kv/mdbx" + "github.com/russross/meddler" "golang.org/x/crypto/sha3" ) -const ( - dbPrefix = "l1infotreesync" - l1InfoTreeSuffix = "-l1infotree" - rollupExitTreeSuffix = "-rollupexittree" - - // infoTable stores the information of L1 Info Tree (the leaves) - // Key: index (uint32 converted to bytes) - // Value: JSON of storeLeaf struct - infoTable = dbPrefix + "-info" - // blockTable stores the first and last index of L1 Info Tree that have been updated on - // Value: JSON of blockWithLeafs - blockTable = dbPrefix + "-block" - // lastBlockTable used to store the last block processed. This is needed to know the last processed blcok - lastBlockTable = dbPrefix + "-lastBlock" - - treeHeight uint8 = 32 -) - var ( ErrBlockNotProcessed = errors.New("given block(s) have not been processed yet") ErrNotFound = errors.New("not found") ErrNoBlock0 = errors.New("blockNum must be greater than 0") - lastBlockKey = []byte("lb") ) type processor struct { - db kv.RwDB + db *sql.DB l1InfoTree *tree.AppendOnlyTree rollupExitTree *tree.UpdatableTree } // UpdateL1InfoTree representation of the UpdateL1InfoTree event type UpdateL1InfoTree struct { + BlockPosition uint64 // TODO: set @ downloader MainnetExitRoot ethCommon.Hash RollupExitRoot ethCommon.Hash ParentHash ethCommon.Hash @@ -60,11 +41,12 @@ type UpdateL1InfoTree struct { // VerifyBatches representation of the VerifyBatches and VerifyBatchesTrustedAggregator events type VerifyBatches struct { - RollupID uint32 - NumBatch uint64 - StateRoot ethCommon.Hash - ExitRoot ethCommon.Hash - Aggregator ethCommon.Address + BlockPosition uint64 // TODO: set @ downloader + RollupID uint32 + NumBatch uint64 + StateRoot ethCommon.Hash + ExitRoot ethCommon.Hash + Aggregator ethCommon.Address } type InitL1InfoRootMap struct { @@ -80,42 +62,28 @@ type Event struct { // L1InfoTreeLeaf representation of a leaf of the L1 Info tree type L1InfoTreeLeaf struct { - L1InfoTreeIndex uint32 - PreviousBlockHash ethCommon.Hash - BlockNumber uint64 - Timestamp uint64 - MainnetExitRoot ethCommon.Hash - RollupExitRoot ethCommon.Hash - GlobalExitRoot ethCommon.Hash -} - -type storeLeaf struct { - BlockNumber uint64 - MainnetExitRoot ethCommon.Hash - RollupExitRoot ethCommon.Hash - ParentHash ethCommon.Hash - Index uint32 - Timestamp uint64 + BlockNumber uint64 `meddler:"block_num"` + BlockPosition uint64 `meddler:"block_pos"` + L1InfoTreeIndex uint32 `meddler:"position"` + PreviousBlockHash ethCommon.Hash `meddler:"previous_block_hash,hash"` + Timestamp uint64 `meddler:"timestamp"` + MainnetExitRoot ethCommon.Hash `meddler:"mainnet_exit_root,hash"` + RollupExitRoot ethCommon.Hash `meddler:"rollup_exit_root,hash"` + GlobalExitRoot ethCommon.Hash `meddler:"global_exit_root,hash"` + Hash ethCommon.Hash `meddler:"hash,hash"` } // Hash as expected by the tree -func (l *storeLeaf) Hash() ethCommon.Hash { +func (l *L1InfoTreeLeaf) hash() ethCommon.Hash { var res [32]byte t := make([]byte, 8) //nolint:gomnd binary.BigEndian.PutUint64(t, l.Timestamp) - copy(res[:], keccak256.Hash(l.GlobalExitRoot().Bytes(), l.ParentHash.Bytes(), t)) + copy(res[:], keccak256.Hash(l.globalExitRoot().Bytes(), l.PreviousBlockHash.Bytes(), t)) return res } -type blockWithLeafs struct { - // inclusive - FirstIndex uint32 - // not inclusive - LastIndex uint32 -} - // GlobalExitRoot returns the GER -func (l *storeLeaf) GlobalExitRoot() ethCommon.Hash { +func (l *L1InfoTreeLeaf) globalExitRoot() ethCommon.Hash { var gerBytes [32]byte hasher := sha3.NewLegacyKeccak256() hasher.Write(l.MainnetExitRoot[:]) @@ -124,57 +92,30 @@ func (l *storeLeaf) GlobalExitRoot() ethCommon.Hash { return gerBytes } -func newProcessor(ctx context.Context, dbPath string) (*processor, error) { - tableCfgFunc := func(defaultBuckets kv.TableCfg) kv.TableCfg { - cfg := kv.TableCfg{ - infoTable: {}, - blockTable: {}, - lastBlockTable: {}, - } - return cfg - } - db, err := mdbx.NewMDBX(nil). - Path(dbPath). - WithTableCfg(tableCfgFunc). - Open() +func newProcessor(dbPath string) (*processor, error) { + err := migrations.RunMigrations(dbPath) if err != nil { return nil, err } - p := &processor{ - db: db, + db, err := db.NewSQLiteDB(dbPath) + if err != nil { + return nil, err } - - // l1InfoTree, err := treeTypes.NewAppendOnlyTree(ctx, db, dbPrefix+l1InfoTreeSuffix) - // p.l1InfoTree = l1InfoTree - // rollupExitTree, err := treeTypes.NewUpdatableTree(ctx, db, dbPrefix+rollupExitTreeSuffix) - // if err != nil { - // return nil, err - // } - // p.rollupExitTree = rollupExitTree - return p, nil + return &processor{ + db: db, + l1InfoTree: tree.NewAppendOnlyTree(db, migrations.L1InfoTreePrefix), + rollupExitTree: tree.NewUpdatableTree(db, migrations.RollupExitTreePrefix), + }, nil } // GetL1InfoTreeMerkleProof creates a merkle proof for the L1 Info tree -func (p *processor) GetL1InfoTreeMerkleProof(ctx context.Context, index uint32) ([32]ethCommon.Hash, ethCommon.Hash, error) { - return tree.EmptyProof, ethCommon.Hash{}, nil - // tx, err := p.db.BeginRo(ctx) - // if err != nil { - // return treeTypes.EmptyProof, ethCommon.Hash{}, err - // } - // defer tx.Rollback() - - // root, err := p.l1InfoTree.GetRootByIndex(tx, index) - // if err != nil { - // return treeTypes.EmptyProof, ethCommon.Hash{}, err - // } - - // proof, err := p.l1InfoTree.GetProof(ctx, index, root) - // if err != nil { - // return treeTypes.EmptyProof, ethCommon.Hash{}, err - // } - - // // TODO: check if we need to return root or wat - // return proof, root, nil +func (p *processor) GetL1InfoTreeMerkleProof(ctx context.Context, index uint32) (treeTypes.Proof, treeTypes.Root, error) { + root, err := p.l1InfoTree.GetRootByIndex(ctx, index) + if err != nil { + return treeTypes.Proof{}, treeTypes.Root{}, err + } + proof, err := p.l1InfoTree.GetProof(ctx, root.Index, root.Hash) + return proof, root, err } // GetLatestInfoUntilBlock returns the most recent L1InfoTreeLeaf that occurred before or at blockNum. @@ -183,11 +124,12 @@ func (p *processor) GetLatestInfoUntilBlock(ctx context.Context, blockNum uint64 if blockNum == 0 { return nil, ErrNoBlock0 } - tx, err := p.db.BeginRo(ctx) + tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return nil, err } defer tx.Rollback() + lpb, err := p.getLastProcessedBlockWithTx(tx) if err != nil { return nil, err @@ -195,29 +137,17 @@ func (p *processor) GetLatestInfoUntilBlock(ctx context.Context, blockNum uint64 if lpb < blockNum { return nil, ErrBlockNotProcessed } - iter, err := tx.RangeDescend(blockTable, common.Uint64ToBytes(blockNum), common.Uint64ToBytes(0), 1) - if err != nil { - return nil, fmt.Errorf( - "error calling RangeDescend(blockTable, %d, 0, 1): %w", blockNum, err, - ) - } - k, v, err := iter.Next() - if err != nil { - return nil, err - } - if k == nil { - return nil, ErrNotFound - } - blk := blockWithLeafs{} - if err := json.Unmarshal(v, &blk); err != nil { - return nil, err - } - return p.getInfoByIndexWithTx(tx, blk.LastIndex-1) + + info := &L1InfoTreeLeaf{} + return info, meddler.QueryRow( + tx, info, + `SELECT * FROM l1info_leaf ORDER BY block_num DESC, block_pos DESC LIMIT 1;`, + ) } // GetInfoByIndex returns the value of a leaf (not the hash) of the L1 info tree func (p *processor) GetInfoByIndex(ctx context.Context, index uint32) (*L1InfoTreeLeaf, error) { - tx, err := p.db.BeginRo(ctx) + tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return nil, err } @@ -225,32 +155,17 @@ func (p *processor) GetInfoByIndex(ctx context.Context, index uint32) (*L1InfoTr return p.getInfoByIndexWithTx(tx, index) } -func (p *processor) getInfoByIndexWithTx(tx kv.Tx, index uint32) (*L1InfoTreeLeaf, error) { - infoBytes, err := tx.GetOne(infoTable, common.Uint32ToBytes(index)) - if err != nil { - return nil, err - } - if infoBytes == nil { - return nil, ErrNotFound - } - var info storeLeaf - if err := json.Unmarshal(infoBytes, &info); err != nil { - return nil, err - } - return &L1InfoTreeLeaf{ - L1InfoTreeIndex: info.Index, - PreviousBlockHash: info.ParentHash, - BlockNumber: info.BlockNumber, - Timestamp: info.Timestamp, - MainnetExitRoot: info.MainnetExitRoot, - RollupExitRoot: info.RollupExitRoot, - GlobalExitRoot: info.GlobalExitRoot(), - }, nil +func (p *processor) getInfoByIndexWithTx(tx *sql.Tx, index uint32) (*L1InfoTreeLeaf, error) { + info := &L1InfoTreeLeaf{} + return info, meddler.QueryRow( + tx, info, + `SELECT * FROM l1info_leaf WHERE position = $1;`, index, + ) } // GetLastProcessedBlock returns the last processed block func (p *processor) GetLastProcessedBlock(ctx context.Context) (uint64, error) { - tx, err := p.db.BeginRo(ctx) + tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return 0, err } @@ -258,77 +173,45 @@ func (p *processor) GetLastProcessedBlock(ctx context.Context) (uint64, error) { return p.getLastProcessedBlockWithTx(tx) } -func (p *processor) getLastProcessedBlockWithTx(tx kv.Tx) (uint64, error) { - blockNumBytes, err := tx.GetOne(lastBlockTable, lastBlockKey) - if err != nil { - return 0, err - } else if blockNumBytes == nil { +func (p *processor) getLastProcessedBlockWithTx(tx *sql.Tx) (uint64, error) { + var lastProcessedBlock uint64 + row := tx.QueryRow("SELECT num FROM BLOCK ORDER BY num DESC LIMIT 1;") + err := row.Scan(&lastProcessedBlock) + if errors.Is(err, sql.ErrNoRows) { return 0, nil } - return common.BytesToUint64(blockNumBytes), nil + return lastProcessedBlock, err } // Reorg triggers a purge and reset process on the processor to leaf it on a state // as if the last block processed was firstReorgedBlock-1 func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { - tx, err := p.db.BeginRw(ctx) - if err != nil { - return err - } - defer tx.Rollback() - c, err := tx.Cursor(blockTable) + tx, err := p.db.BeginTx(ctx, nil) if err != nil { return err } - defer c.Close() - firstKey := common.Uint64ToBytes(firstReorgedBlock) - firstReorgedL1InfoTreeIndex := int64(-1) - for blkKey, blkValue, err := c.Seek(firstKey); blkKey != nil; blkKey, blkValue, err = c.Next() { + defer func() { if err != nil { - tx.Rollback() - return err - } - var blk blockWithLeafs - if err := json.Unmarshal(blkValue, &blk); err != nil { - tx.Rollback() - return err - } - for i := blk.FirstIndex; i < blk.LastIndex; i++ { - if firstReorgedL1InfoTreeIndex == -1 { - firstReorgedL1InfoTreeIndex = int64(i) + if errRllbck := tx.Rollback(); errRllbck != nil { + log.Errorf("error while rolling back tx %v", errRllbck) } - if err := p.deleteLeaf(tx, i); err != nil { - tx.Rollback() - return err - } - } - if err := tx.Delete(blockTable, blkKey); err != nil { - tx.Rollback() - return err } - } - if err := p.updateLastProcessedBlock(tx, firstReorgedBlock-1); err != nil { - tx.Rollback() + }() + + _, err = tx.Exec(`DELETE FROM block WHERE num >= $1;`, firstReorgedBlock) + if err != nil { return err } - var rollbackL1InfoTree func() - if firstReorgedL1InfoTreeIndex != -1 { - // rollbackL1InfoTree, err = p.l1InfoTree.Reorg(tx, uint32(firstReorgedL1InfoTreeIndex)) - // if err != nil { - // tx.Rollback() - // rollbackL1InfoTree() - // return err - // } + + if err = p.l1InfoTree.Reorg(tx, firstReorgedBlock); err != nil { + return err } - if err := tx.Commit(); err != nil { - rollbackL1InfoTree() + + if err = p.rollupExitTree.Reorg(tx, firstReorgedBlock); err != nil { return err } - return nil -} -func (p *processor) deleteLeaf(tx kv.RwTx, index uint32) error { - if err := tx.Delete(infoTable, common.Uint32ToBytes(index)); err != nil { + if err := tx.Commit(); err != nil { return err } return nil @@ -337,146 +220,91 @@ func (p *processor) deleteLeaf(tx kv.RwTx, index uint32) error { // ProcessBlock process the events of the block to build the rollup exit tree and the l1 info tree // and updates the last processed block (can be called without events for that purpose) func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { - tx, err := p.db.BeginRw(ctx) + tx, err := p.db.BeginTx(ctx, nil) if err != nil { return err } - events := make([]Event, len(b.Events)) - rollupExitTreeRollback := func() {} - l1InfoTreeRollback := func() {} - rollback := func() { - tx.Rollback() - rollupExitTreeRollback() - l1InfoTreeRollback() - } - l1InfoTreeLeavesToAdd := []treeTypes.Leaf{} - rollupExitTreeLeavesToAdd := []treeTypes.Leaf{} - if len(b.Events) > 0 { - var initialL1InfoIndex uint32 - var l1InfoLeavesAdded uint32 - lastIndex, err := p.getLastIndex(tx) - if err == ErrNotFound { - initialL1InfoIndex = 0 - } else if err != nil { - rollback() - return err - } else { - initialL1InfoIndex = lastIndex + 1 - } - for _, e := range b.Events { - event := e.(Event) - events = append(events, event) - if event.UpdateL1InfoTree != nil { - index := initialL1InfoIndex + l1InfoLeavesAdded - leafToStore := storeLeaf{ - BlockNumber: b.Num, - Index: index, - MainnetExitRoot: event.UpdateL1InfoTree.MainnetExitRoot, - RollupExitRoot: event.UpdateL1InfoTree.RollupExitRoot, - ParentHash: event.UpdateL1InfoTree.ParentHash, - Timestamp: event.UpdateL1InfoTree.Timestamp, - } - if err := p.storeLeafInfo(tx, leafToStore); err != nil { - rollback() - return err - } - l1InfoTreeLeavesToAdd = append(l1InfoTreeLeavesToAdd, treeTypes.Leaf{ - Index: leafToStore.Index, - Hash: leafToStore.Hash(), - }) - l1InfoLeavesAdded++ + defer func() { + if err != nil { + if errRllbck := tx.Rollback(); errRllbck != nil { + log.Errorf("error while rolling back tx %v", errRllbck) } + } + }() - if event.VerifyBatches != nil { - rollupExitTreeLeavesToAdd = append(rollupExitTreeLeavesToAdd, treeTypes.Leaf{ - Index: event.VerifyBatches.RollupID - 1, - Hash: event.VerifyBatches.ExitRoot, - }) - } + if _, err := tx.Exec(`INSERT INTO block (num) VALUES ($1)`, b.Num); err != nil { + return err + } - if event.InitL1InfoRootMap != nil { - // TODO: indicate that l1 Info tree indexes before the one on this - // event are not safe to use - log.Debugf("TODO: handle InitL1InfoRootMap event") + var initialL1InfoIndex uint32 + var l1InfoLeavesAdded uint32 + lastIndex, err := p.getLastIndex(tx) + if err == ErrNotFound { + initialL1InfoIndex = 0 + } else if err != nil { + return err + } else { + initialL1InfoIndex = lastIndex + 1 + } + for _, e := range b.Events { + event := e.(Event) + if event.UpdateL1InfoTree != nil { + index := initialL1InfoIndex + l1InfoLeavesAdded + info := &L1InfoTreeLeaf{ + BlockNumber: b.Num, + BlockPosition: event.UpdateL1InfoTree.BlockPosition, + L1InfoTreeIndex: index, + PreviousBlockHash: event.UpdateL1InfoTree.ParentHash, + Timestamp: event.UpdateL1InfoTree.Timestamp, + MainnetExitRoot: event.UpdateL1InfoTree.MainnetExitRoot, + RollupExitRoot: event.UpdateL1InfoTree.RollupExitRoot, } - } - if l1InfoLeavesAdded > 0 { - bwl := blockWithLeafs{ - FirstIndex: initialL1InfoIndex, - LastIndex: initialL1InfoIndex + l1InfoLeavesAdded, + info.GlobalExitRoot = info.globalExitRoot() + info.Hash = info.hash() + err = meddler.Insert(tx, "l1info_leaf", info) + if err != nil { + return err } - blockValue, err := json.Marshal(bwl) + err = p.l1InfoTree.AddLeaf(tx, info.BlockNumber, info.BlockPosition, treeTypes.Leaf{ + Index: info.L1InfoTreeIndex, + Hash: info.Hash, + }) if err != nil { - rollback() return err } - if err := tx.Put(blockTable, common.Uint64ToBytes(b.Num), blockValue); err != nil { - rollback() + l1InfoLeavesAdded++ + } + + if event.VerifyBatches != nil { + err = p.rollupExitTree.UpsertLeaf(tx, b.Num, event.VerifyBatches.BlockPosition, treeTypes.Leaf{ + Index: event.VerifyBatches.RollupID - 1, + Hash: event.VerifyBatches.ExitRoot, + }) + if err != nil { return err } - // l1InfoTreeRollback, err = p.l1InfoTree.AddLeaves(tx, l1InfoTreeLeavesToAdd) - // if err != nil { - // rollback() - // return err - // } } - if len(rollupExitTreeLeavesToAdd) > 0 { - // rollupExitTreeRollback, err = p.rollupExitTree.UpseartLeaves(tx, rollupExitTreeLeavesToAdd, b.Num) - // if err != nil { - // rollback() - // return err - // } + if event.InitL1InfoRootMap != nil { + // TODO: indicate that l1 Info tree indexes before the one on this + // event are not safe to use + log.Debugf("TODO: handle InitL1InfoRootMap event") } } - if err := p.updateLastProcessedBlock(tx, b.Num); err != nil { - rollback() - return err - } if err := tx.Commit(); err != nil { - rollback() return err } - log.Infof("block %d processed with events: %+v", b.Num, events) + log.Infof("block %d processed with %d events", b.Num, len(b.Events)) return nil } -func (p *processor) getLastIndex(tx kv.Tx) (uint32, error) { - bNum, err := p.getLastProcessedBlockWithTx(tx) - if err != nil { - return 0, err - } - if bNum == 0 { - return 0, nil - } - iter, err := tx.RangeDescend(blockTable, common.Uint64ToBytes(bNum), common.Uint64ToBytes(0), 1) - if err != nil { - return 0, err - } - _, blkBytes, err := iter.Next() - if err != nil { - return 0, err - } - if blkBytes == nil { +func (p *processor) getLastIndex(tx *sql.Tx) (uint32, error) { + var lastProcessedIndex uint32 + row := tx.QueryRow("SELECT position FROM l1info_leaf ORDER BY block_num DESC, block_pos DESC LIMIT 1;") + err := row.Scan(&lastProcessedIndex) + if errors.Is(err, sql.ErrNoRows) { return 0, ErrNotFound } - var blk blockWithLeafs - if err := json.Unmarshal(blkBytes, &blk); err != nil { - return 0, err - } - return blk.LastIndex - 1, nil -} - -func (p *processor) storeLeafInfo(tx kv.RwTx, leaf storeLeaf) error { - leafValue, err := json.Marshal(leaf) - if err != nil { - return err - } - return tx.Put(infoTable, common.Uint32ToBytes(leaf.Index), leafValue) -} - -func (p *processor) updateLastProcessedBlock(tx kv.RwTx, blockNum uint64) error { - blockNumBytes := common.Uint64ToBytes(blockNum) - return tx.Put(lastBlockTable, lastBlockKey, blockNumBytes) + return lastProcessedIndex, err } diff --git a/sync/evmdriver.go b/sync/evmdriver.go index 2edd2e15..79ed859b 100644 --- a/sync/evmdriver.go +++ b/sync/evmdriver.go @@ -122,7 +122,7 @@ func (d *EVMDriver) handleNewBlock(ctx context.Context, b EVMBlock) { err := d.processor.ProcessBlock(ctx, blockToProcess) if err != nil { attempts++ - d.log.Errorf("error processing events for blcok %d, err: ", b.Num, err) + d.log.Errorf("error processing events for block %d, err: ", b.Num, err) d.rh.Handle("handleNewBlock", attempts) continue } diff --git a/test/helpers/aggoracle_e2e.go b/test/helpers/aggoracle_e2e.go index fdde39dd..0c1cc1f4 100644 --- a/test/helpers/aggoracle_e2e.go +++ b/test/helpers/aggoracle_e2e.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "math/big" + "path" "testing" "time" @@ -104,7 +105,7 @@ func CommonSetup(t *testing.T) ( reorg, err := reorgdetector.New(l1Client.Client(), reorgdetector.Config{DBPath: dbPathReorgDetector}) require.NoError(t, err) // Syncer - dbPathSyncer := t.TempDir() + dbPathSyncer := path.Join(t.TempDir(), "tmp.sqlite") syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerL1Addr, common.Address{}, 10, etherman.LatestBlock, reorg, l1Client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3) require.NoError(t, err) go syncer.Start(ctx) diff --git a/tree/appendonlytree.go b/tree/appendonlytree.go index 550b9b5f..14ec3bc7 100644 --- a/tree/appendonlytree.go +++ b/tree/appendonlytree.go @@ -16,9 +16,12 @@ type AppendOnlyTree struct { } // NewAppendOnlyTree creates a AppendOnlyTree -func NewAppendOnlyTree(db *sql.DB) *AppendOnlyTree { - t := newTree(db) - return &AppendOnlyTree{Tree: t} +func NewAppendOnlyTree(db *sql.DB, dbPrefix string) *AppendOnlyTree { + t := newTree(db, dbPrefix) + return &AppendOnlyTree{ + Tree: t, + lastIndex: -2, + } } func (t *AppendOnlyTree) AddLeaf(tx *sql.Tx, blockNum, blockPosition uint64, leaf types.Leaf) error { diff --git a/tree/migrations/migrations.go b/tree/migrations/migrations.go index 98656ae9..ffdb1d0e 100644 --- a/tree/migrations/migrations.go +++ b/tree/migrations/migrations.go @@ -9,7 +9,10 @@ import ( _ "embed" ) -const upDownSeparator = "-- +migrate Up" +const ( + upDownSeparator = "-- +migrate Up" + dbPrefixReplacer = "/*dbprefix*/" +) //go:embed tree0001.sql var mig001 string @@ -28,3 +31,13 @@ var Migrations = &migrate.MemoryMigrationSource{ func RunMigrations(dbPath string) error { return db.RunMigrations(dbPath, Migrations) } + +func MigrationsWithPrefix(prefix string) []*migrate.Migration { + return []*migrate.Migration{ + { + Id: prefix + "tree001", + Up: []string{strings.Replace(mig001splitted[1], dbPrefixReplacer, prefix, -1)}, + Down: []string{strings.Replace(mig001splitted[0], dbPrefixReplacer, prefix, -1)}, + }, + } +} diff --git a/tree/migrations/tree0001.sql b/tree/migrations/tree0001.sql index bc2e6751..f70d048e 100644 --- a/tree/migrations/tree0001.sql +++ b/tree/migrations/tree0001.sql @@ -1,16 +1,16 @@ -- +migrate Down -DROP TABLE IF EXISTS root; -DROP TABLE IF EXISTS rht; +DROP TABLE IF EXISTS /*dbprefix*/root; +DROP TABLE IF EXISTS /*dbprefix*/rht; -- +migrate Up -CREATE TABLE root ( +CREATE TABLE /*dbprefix*/root ( hash VARCHAR PRIMARY KEY, - position INTEGER NOT NULL UNIQUE, + position INTEGER NOT NULL, block_num BIGINT NOT NULL, block_position BIGINT NOT NULL ); -CREATE TABLE rht ( +CREATE TABLE /*dbprefix*/rht ( hash VARCHAR PRIMARY KEY, left VARCHAR NOT NULL, right VARCHAR NOT NULL diff --git a/tree/tree.go b/tree/tree.go index 5bee7c07..991faf72 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -22,6 +22,8 @@ var ( type Tree struct { db *sql.DB zeroHashes []common.Hash + rhtTable string + rootTable string } func newTreeNode(left, right common.Hash) types.TreeNode { @@ -37,10 +39,12 @@ func newTreeNode(left, right common.Hash) types.TreeNode { } } -func newTree(db *sql.DB) *Tree { +func newTree(db *sql.DB, tablePrefix string) *Tree { t := &Tree{ db: db, zeroHashes: generateZeroHashes(types.DefaultHeight), + rhtTable: tablePrefix + "rht", + rootTable: tablePrefix + "root", } return t @@ -104,25 +108,29 @@ func (t *Tree) getSiblings(tx *sql.Tx, index uint32, root common.Hash) ( } // GetProof returns the merkle proof for a given index and root. -func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) ([types.DefaultHeight]common.Hash, error) { - tx, err := t.db.BeginTx(ctx, nil) +func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) (types.Proof, error) { + tx, err := t.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { - return [types.DefaultHeight]common.Hash{}, err + return types.Proof{}, err } defer tx.Rollback() siblings, isErrNotFound, err := t.getSiblings(tx, index, root) if err != nil { - return [types.DefaultHeight]common.Hash{}, err + return types.Proof{}, err } if isErrNotFound { - return [types.DefaultHeight]common.Hash{}, ErrNotFound + return types.Proof{}, ErrNotFound } return siblings, nil } func (t *Tree) getRHTNode(tx *sql.Tx, nodeHash common.Hash) (*types.TreeNode, error) { node := &types.TreeNode{} - err := meddler.QueryRow(tx, node, `select * from rht where hash = $1`, nodeHash) + err := meddler.QueryRow( + tx, node, + fmt.Sprintf(`select * from %s where hash = $1`, t.rhtTable), + nodeHash.Hex(), + ) if err != nil { if errors.Is(err, sql.ErrNoRows) { return node, ErrNotFound @@ -151,7 +159,7 @@ func generateZeroHashes(height uint8) []common.Hash { func (t *Tree) storeNodes(tx *sql.Tx, nodes []types.TreeNode) error { for _, node := range nodes { - if err := meddler.Insert(tx, "rht", &node); err != nil { + if err := meddler.Insert(tx, t.rhtTable, &node); err != nil { if sqliteErr, ok := db.SQLiteErr(err); ok { if sqliteErr.Code() == sqlite3.SQLITE_CONSTRAINT_PRIMARYKEY { // ignore repeated entries. This is likely to happen due to not @@ -166,12 +174,12 @@ func (t *Tree) storeNodes(tx *sql.Tx, nodes []types.TreeNode) error { } func (t *Tree) storeRoot(tx *sql.Tx, root types.Root) error { - return meddler.Insert(tx, "root", &root) + return meddler.Insert(tx, t.rootTable, &root) } // GetLastRoot returns the last processed root func (t *Tree) GetLastRoot(ctx context.Context) (types.Root, error) { - tx, err := t.db.BeginTx(ctx, nil) + tx, err := t.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return types.Root{}, err } @@ -181,7 +189,10 @@ func (t *Tree) GetLastRoot(ctx context.Context) (types.Root, error) { func (t *Tree) getLastRootWithTx(tx *sql.Tx) (types.Root, error) { var root types.Root - err := meddler.QueryRow(tx, &root, `SELECT * FROM root ORDER BY block_num DESC, block_position DESC LIMIT 1;`) + err := meddler.QueryRow( + tx, &root, + fmt.Sprintf(`SELECT * FROM %s ORDER BY block_num DESC, block_position DESC LIMIT 1;`, t.rootTable), + ) if err != nil { if errors.Is(err, sql.ErrNoRows) { return root, ErrNotFound @@ -193,14 +204,18 @@ func (t *Tree) getLastRootWithTx(tx *sql.Tx) (types.Root, error) { // GetRootByIndex returns the root associated to the index func (t *Tree) GetRootByIndex(ctx context.Context, index uint32) (types.Root, error) { - tx, err := t.db.BeginTx(ctx, nil) + tx, err := t.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return types.Root{}, err } defer tx.Rollback() var root types.Root - err = meddler.QueryRow(tx, &root, `SELECT * FROM root WHERE position = $1;`, index) + err = meddler.QueryRow( + tx, &root, + fmt.Sprintf(`SELECT * FROM %s WHERE position = $1;`, t.rootTable), + index, + ) if err != nil { if errors.Is(err, sql.ErrNoRows) { return root, ErrNotFound @@ -212,14 +227,18 @@ func (t *Tree) GetRootByIndex(ctx context.Context, index uint32) (types.Root, er // GetRootByHash returns the root associated to the hash func (t *Tree) GetRootByHash(ctx context.Context, hash common.Hash) (types.Root, error) { - tx, err := t.db.BeginTx(ctx, nil) + tx, err := t.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return types.Root{}, err } defer tx.Rollback() var root types.Root - err = meddler.QueryRow(tx, &root, `SELECT * FROM root WHERE hash = $1;`, hash) + err = meddler.QueryRow( + tx, &root, + fmt.Sprintf(`SELECT * FROM %s WHERE hash = $1;`, t.rootTable), + hash.Hex(), + ) if err != nil { if errors.Is(err, sql.ErrNoRows) { return root, ErrNotFound @@ -230,7 +249,7 @@ func (t *Tree) GetRootByHash(ctx context.Context, hash common.Hash) (types.Root, } func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (common.Hash, error) { - tx, err := t.db.BeginTx(ctx, nil) + tx, err := t.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return common.Hash{}, err } @@ -253,8 +272,11 @@ func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (com } // Reorg deletes all the data relevant from firstReorgedBlock (includded) and onwards -func (t *AppendOnlyTree) Reorg(tx *sql.Tx, firstReorgedBlock uint64) error { - _, err := tx.Exec(`DELETE FROM root WHERE block_num >= $1`, firstReorgedBlock) +func (t *Tree) Reorg(tx *sql.Tx, firstReorgedBlock uint64) error { + _, err := tx.Exec( + fmt.Sprintf(`DELETE FROM %s WHERE block_num >= $1`, t.rootTable), + firstReorgedBlock, + ) return err // NOTE: rht is not cleaned, this could be done in the future as optimization } diff --git a/tree/tree_test.go b/tree/tree_test.go index 702ee13d..d77785c1 100644 --- a/tree/tree_test.go +++ b/tree/tree_test.go @@ -35,7 +35,7 @@ func TestMTAddLeaf(t *testing.T) { require.NoError(t, err) db, err := db.NewSQLiteDB(dbPath) require.NoError(t, err) - merkletree := tree.NewAppendOnlyTree(db) + merkletree := tree.NewAppendOnlyTree(db, "") // Add exisiting leaves tx, err := db.BeginTx(ctx, nil) @@ -87,7 +87,7 @@ func TestMTGetProof(t *testing.T) { require.NoError(t, err) db, err := db.NewSQLiteDB(dbPath) require.NoError(t, err) - tre := tree.NewAppendOnlyTree(db) + tre := tree.NewAppendOnlyTree(db, "") tx, err := db.BeginTx(ctx, nil) require.NoError(t, err) diff --git a/tree/types/types.go b/tree/types/types.go index 09a06ba3..bb117342 100644 --- a/tree/types/types.go +++ b/tree/types/types.go @@ -12,16 +12,16 @@ type Leaf struct { } type Root struct { - Hash common.Hash `meddler:"hash"` + Hash common.Hash `meddler:"hash,hash"` Index uint32 `meddler:"position"` BlockNum uint64 `meddler:"block_num"` BlockPosition uint64 `meddler:"block_position"` } type TreeNode struct { - Hash common.Hash `meddler:"hash"` - Left common.Hash `meddler:"left"` - Right common.Hash `meddler:"right"` + Hash common.Hash `meddler:"hash,hash"` + Left common.Hash `meddler:"left,hash"` + Right common.Hash `meddler:"right,hash"` } type Proof [DefaultHeight]common.Hash diff --git a/tree/updatabletree.go b/tree/updatabletree.go index b13970f2..1f85c36a 100644 --- a/tree/updatabletree.go +++ b/tree/updatabletree.go @@ -4,6 +4,7 @@ import ( "database/sql" "github.com/0xPolygon/cdk/tree/types" + "github.com/ethereum/go-ethereum/common" ) // UpdatableTree is a tree that have updatable leaves, and doesn't need to have sequential inserts @@ -12,20 +13,27 @@ type UpdatableTree struct { } // NewUpdatableTree returns an UpdatableTree -func NewUpdatableTree(db *sql.DB) (*UpdatableTree, error) { - t := newTree(db) +func NewUpdatableTree(db *sql.DB, dbPrefix string) *UpdatableTree { + t := newTree(db, dbPrefix) ut := &UpdatableTree{ Tree: t, } - return ut, nil + return ut } func (t *UpdatableTree) UpsertLeaf(tx *sql.Tx, blockNum, blockPosition uint64, leaf types.Leaf) error { + var rootHash common.Hash root, err := t.getLastRootWithTx(tx) if err != nil { - return err + if err == ErrNotFound { + rootHash = t.zeroHashes[types.DefaultHeight] + } else { + return err + } + } else { + rootHash = root.Hash } - siblings, _, err := t.getSiblings(tx, leaf.Index, root.Hash) + siblings, _, err := t.getSiblings(tx, leaf.Index, rootHash) if err != nil { return err } From 10b17f97672c7e469b051ae184eff6e752c56ca0 Mon Sep 17 00:00:00 2001 From: Arnau Date: Wed, 4 Sep 2024 17:00:03 +0200 Subject: [PATCH 15/31] minor cleaning --- bridgesync/migrations/bridgesync0001.sql | 16 +++++++------- db/config.go | 25 ---------------------- db/logger.go | 27 ------------------------ go.mod | 2 -- go.sum | 4 ---- l1infotreesync/processor.go | 4 ++-- tree/migrations/tree001_test.go | 1 - 7 files changed, 10 insertions(+), 69 deletions(-) delete mode 100644 db/config.go delete mode 100644 db/logger.go delete mode 100644 tree/migrations/tree001_test.go diff --git a/bridgesync/migrations/bridgesync0001.sql b/bridgesync/migrations/bridgesync0001.sql index b86d9243..de90910c 100644 --- a/bridgesync/migrations/bridgesync0001.sql +++ b/bridgesync/migrations/bridgesync0001.sql @@ -9,9 +9,9 @@ CREATE TABLE block ( ); CREATE TABLE bridge ( - block_num INTEGER NOT NULL REFERENCES block(num) ON DELETE CASCADE, - block_pos INTEGER NOT NULL, - leaf_type INTEGER NOT NULL, + block_num INTEGER NOT NULL REFERENCES block(num) ON DELETE CASCADE, + block_pos INTEGER NOT NULL, + leaf_type INTEGER NOT NULL, origin_network INTEGER NOT NULL, origin_address VARCHAR NOT NULL, destination_network INTEGER NOT NULL, @@ -19,13 +19,13 @@ CREATE TABLE bridge ( amount DECIMAL(78, 0) NOT NULL, metadata BLOB, deposit_count INTEGER NOT NULL, - PRIMARY KEY (block_num, block_pos) + PRIMARY KEY (block_num, block_pos) ); CREATE TABLE claim ( - block_num INTEGER NOT NULL REFERENCES block(num) ON DELETE CASCADE, - block_pos INTEGER NOT NULL, - global_index DECIMAL(78, 0) NOT NULL, + block_num INTEGER NOT NULL REFERENCES block(num) ON DELETE CASCADE, + block_pos INTEGER NOT NULL, + global_index DECIMAL(78, 0) NOT NULL, origin_network INTEGER NOT NULL, origin_address VARCHAR NOT NULL, destination_address VARCHAR NOT NULL, @@ -38,5 +38,5 @@ CREATE TABLE claim ( destination_network INTEGER NOT NULL, metadata BLOB, is_message BOOLEAN, - PRIMARY KEY (block_num, block_pos) + PRIMARY KEY (block_num, block_pos) ); \ No newline at end of file diff --git a/db/config.go b/db/config.go deleted file mode 100644 index ad56155f..00000000 --- a/db/config.go +++ /dev/null @@ -1,25 +0,0 @@ -package db - -// Config provide fields to configure the pool -type Config struct { - // Database name - Name string `mapstructure:"Name"` - - // Database User name - User string `mapstructure:"User"` - - // Database Password of the user - Password string `mapstructure:"Password"` - - // Host address of database - Host string `mapstructure:"Host"` - - // Port Number of database - Port string `mapstructure:"Port"` - - // EnableLog - EnableLog bool `mapstructure:"EnableLog"` - - // MaxConns is the maximum number of connections in the pool. - MaxConns int `mapstructure:"MaxConns"` -} diff --git a/db/logger.go b/db/logger.go deleted file mode 100644 index 9478477f..00000000 --- a/db/logger.go +++ /dev/null @@ -1,27 +0,0 @@ -package db - -import ( - "context" - - "github.com/jackc/pgx" -) - -type logger struct{} - -func (l logger) Log(ctx context.Context, level pgx.LogLevel, msg string, data map[string]interface{}) { - // TODO: adapt to sqlite - - // m := fmt.Sprintf("%s %v", msg, data) - - // switch level { - // case pgx.LogLevelInfo: - // log.Info(m) - // case pgx.LogLevelWarn: - // log.Warn(m) - // case pgx.LogLevelError: - // log.Error(m) - // default: - // m = fmt.Sprintf("%s %s %v", level.String(), msg, data) - // log.Debug(m) - // } -} diff --git a/go.mod b/go.mod index f85b4f26..5c8b62fb 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,6 @@ require ( github.com/iden3/go-iden3-crypto v0.0.16 github.com/invopop/jsonschema v0.12.0 github.com/jackc/pgconn v1.14.3 - github.com/jackc/pgx v3.6.2+incompatible github.com/jackc/pgx/v4 v4.18.3 github.com/ledgerwatch/erigon-lib v1.0.0 github.com/mitchellh/mapstructure v1.5.0 @@ -90,7 +89,6 @@ require ( github.com/holiman/uint256 v1.2.4 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.3.3 // indirect diff --git a/go.sum b/go.sum index 652a5a5d..0e128772 100644 --- a/go.sum +++ b/go.sum @@ -202,8 +202,6 @@ github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9 github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= @@ -238,8 +236,6 @@ github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrU github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o= -github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index f1b33cfe..b27ca86d 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -32,7 +32,7 @@ type processor struct { // UpdateL1InfoTree representation of the UpdateL1InfoTree event type UpdateL1InfoTree struct { - BlockPosition uint64 // TODO: set @ downloader + BlockPosition uint64 MainnetExitRoot ethCommon.Hash RollupExitRoot ethCommon.Hash ParentHash ethCommon.Hash @@ -41,7 +41,7 @@ type UpdateL1InfoTree struct { // VerifyBatches representation of the VerifyBatches and VerifyBatchesTrustedAggregator events type VerifyBatches struct { - BlockPosition uint64 // TODO: set @ downloader + BlockPosition uint64 RollupID uint32 NumBatch uint64 StateRoot ethCommon.Hash diff --git a/tree/migrations/tree001_test.go b/tree/migrations/tree001_test.go deleted file mode 100644 index a6ea3eef..00000000 --- a/tree/migrations/tree001_test.go +++ /dev/null @@ -1 +0,0 @@ -package migrations From 6e078038381845f2413e0470e1bfb664541a4a01 Mon Sep 17 00:00:00 2001 From: Arnau Date: Wed, 4 Sep 2024 17:21:32 +0200 Subject: [PATCH 16/31] add GetBlockByLER func --- bridgesync/bridgesync.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bridgesync/bridgesync.go b/bridgesync/bridgesync.go index f91be313..ff105bb9 100644 --- a/bridgesync/bridgesync.go +++ b/bridgesync/bridgesync.go @@ -171,3 +171,11 @@ func (s *BridgeSync) GetBridges(ctx context.Context, fromBlock, toBlock uint64) func (s *BridgeSync) GetProof(ctx context.Context, depositCount uint32, localExitRoot common.Hash) ([32]common.Hash, error) { return s.processor.exitTree.GetProof(ctx, depositCount, localExitRoot) } + +func (p *processor) GetBlockByLER(ctx context.Context, ler common.Hash) (uint64, error) { + root, err := p.exitTree.GetRootByHash(ctx, ler) + if err != nil { + return 0, err + } + return root.BlockNum, nil +} From a90926c3977b16d9341fbdee595d9b49fe42a0ef Mon Sep 17 00:00:00 2001 From: Arnau Date: Wed, 4 Sep 2024 18:37:27 +0200 Subject: [PATCH 17/31] handle err not found --- l1infotreesync/processor.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index b27ca86d..d5b8b053 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -139,10 +139,17 @@ func (p *processor) GetLatestInfoUntilBlock(ctx context.Context, blockNum uint64 } info := &L1InfoTreeLeaf{} - return info, meddler.QueryRow( + err = meddler.QueryRow( tx, info, `SELECT * FROM l1info_leaf ORDER BY block_num DESC, block_pos DESC LIMIT 1;`, ) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrNotFound + } + return nil, err + } + return info, nil } // GetInfoByIndex returns the value of a leaf (not the hash) of the L1 info tree From d0b035de64417cc182b384f3f38be3c4a4a49641 Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 5 Sep 2024 12:13:38 +0200 Subject: [PATCH 18/31] merge develop --- go.mod | 4 ++++ go.sum | 4 ++-- tree/appendonlytree.go | 26 +++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a421934a..b489c734 100644 --- a/go.mod +++ b/go.mod @@ -148,7 +148,11 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a // indirect diff --git a/go.sum b/go.sum index eb8f5661..e2888e50 100644 --- a/go.sum +++ b/go.sum @@ -539,8 +539,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/tree/appendonlytree.go b/tree/appendonlytree.go index befb45c6..14ec3bc7 100644 --- a/tree/appendonlytree.go +++ b/tree/appendonlytree.go @@ -11,7 +11,7 @@ import ( // AppendOnlyTree is a tree where leaves are added sequentially (by index) type AppendOnlyTree struct { *Tree - lastLeftCache types.Proof + lastLeftCache [types.DefaultHeight]common.Hash lastIndex int64 } @@ -24,7 +24,31 @@ func NewAppendOnlyTree(db *sql.DB, dbPrefix string) *AppendOnlyTree { } } +func (t *AppendOnlyTree) AddLeaf(tx *sql.Tx, blockNum, blockPosition uint64, leaf types.Leaf) error { if int64(leaf.Index) != t.lastIndex+1 { + // rebuild cache + if err := t.initCache(tx); err != nil { + return err + } + if int64(leaf.Index) != t.lastIndex+1 { + return fmt.Errorf( + "mismatched index. Expected: %d, actual: %d", + t.lastIndex+1, leaf.Index, + ) + } + } + // Calculate new tree nodes + currentChildHash := leaf.Hash + newNodes := []types.TreeNode{} + for h := uint8(0); h < types.DefaultHeight; h++ { + var parent types.TreeNode + if leaf.Index&(1< 0 { + // Add child to the right + parent = newTreeNode(t.lastLeftCache[h], currentChildHash) + } else { + // Add child to the left + parent = newTreeNode(currentChildHash, t.zeroHashes[h]) + // Update cache t.lastLeftCache[h] = currentChildHash } currentChildHash = parent.Hash From c245cfd8131c09ba800ad306ce3b2e704b544fca Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 5 Sep 2024 12:42:06 +0200 Subject: [PATCH 19/31] use memory for sqlite on the tests --- bridgesync/e2e_test.go | 2 +- bridgesync/migrations/bridgesync0001_test.go | 2 +- bridgesync/processor_test.go | 2 +- claimsponsor/e2e_test.go | 2 +- l1bridge2infoindexsync/e2e_test.go | 4 ++-- l1infotreesync/e2e_test.go | 4 ++-- test/helpers/aggoracle_e2e.go | 2 +- tree/tree_test.go | 6 ++++-- 8 files changed, 13 insertions(+), 11 deletions(-) diff --git a/bridgesync/e2e_test.go b/bridgesync/e2e_test.go index f3f64969..9f0d2d7e 100644 --- a/bridgesync/e2e_test.go +++ b/bridgesync/e2e_test.go @@ -46,7 +46,7 @@ func newSimulatedClient(t *testing.T, auth *bind.TransactOpts) ( func TestBridgeEventE2E(t *testing.T) { ctx := context.Background() - dbPathSyncer := path.Join(t.TempDir(), "tmp.sqlite") + dbPathSyncer := path.Join(t.TempDir(), "file::memory:?cache=shared") dbPathReorg := t.TempDir() privateKey, err := crypto.GenerateKey() require.NoError(t, err) diff --git a/bridgesync/migrations/bridgesync0001_test.go b/bridgesync/migrations/bridgesync0001_test.go index 10355e37..d117e0e2 100644 --- a/bridgesync/migrations/bridgesync0001_test.go +++ b/bridgesync/migrations/bridgesync0001_test.go @@ -10,7 +10,7 @@ import ( ) func Test001(t *testing.T) { - dbPath := path.Join(t.TempDir(), "tmp.db") + dbPath := path.Join(t.TempDir(), "file::memory:?cache=shared") err := RunMigrations(dbPath) require.NoError(t, err) diff --git a/bridgesync/processor_test.go b/bridgesync/processor_test.go index 9bcdc628..077c9c65 100644 --- a/bridgesync/processor_test.go +++ b/bridgesync/processor_test.go @@ -19,7 +19,7 @@ import ( ) func TestProceessor(t *testing.T) { - path := path.Join(t.TempDir(), "tmp.sqlite") + path := path.Join(t.TempDir(), "file::memory:?cache=shared") log.Debugf("sqlite path: %s", path) err := migrationsBridge.RunMigrations(path) require.NoError(t, err) diff --git a/claimsponsor/e2e_test.go b/claimsponsor/e2e_test.go index 433755b4..c8e58679 100644 --- a/claimsponsor/e2e_test.go +++ b/claimsponsor/e2e_test.go @@ -22,7 +22,7 @@ func TestE2EL1toEVML2(t *testing.T) { // start other needed components ctx := context.Background() env := helpers.SetupAggoracleWithEVMChain(t) - dbPathBridgeSyncL1 := path.Join(t.TempDir(), "tmp.sqlite") + dbPathBridgeSyncL1 := path.Join(t.TempDir(), "file::memory:?cache=shared") testClient := helpers.TestClient{ClientRenamed: env.L1Client.Client()} bridgeSyncL1, err := bridgesync.NewL1(ctx, dbPathBridgeSyncL1, env.BridgeL1Addr, 10, etherman.LatestBlock, env.ReorgDetector, testClient, 0, time.Millisecond*10, 0, 0) require.NoError(t, err) diff --git a/l1bridge2infoindexsync/e2e_test.go b/l1bridge2infoindexsync/e2e_test.go index 601385c8..3583aecf 100644 --- a/l1bridge2infoindexsync/e2e_test.go +++ b/l1bridge2infoindexsync/e2e_test.go @@ -120,8 +120,8 @@ func newSimulatedClient(authDeployer, authCaller *bind.TransactOpts) ( func TestE2E(t *testing.T) { ctx := context.Background() - dbPathBridgeSync := path.Join(t.TempDir(), "tmp.sqlite") - dbPathL1Sync := path.Join(t.TempDir(), "tmp.sqlite") + dbPathBridgeSync := path.Join(t.TempDir(), "file::memory:?cache=shared") + dbPathL1Sync := path.Join(t.TempDir(), "file::memory:?cache=shared") dbPathReorg := t.TempDir() dbPathL12InfoSync := t.TempDir() diff --git a/l1infotreesync/e2e_test.go b/l1infotreesync/e2e_test.go index 5ac6ac21..29d5f1b3 100644 --- a/l1infotreesync/e2e_test.go +++ b/l1infotreesync/e2e_test.go @@ -69,7 +69,7 @@ func newSimulatedClient(auth *bind.TransactOpts) ( func TestE2E(t *testing.T) { ctx := context.Background() - dbPath := path.Join(t.TempDir(), "tmp.sqlite") + dbPath := path.Join(t.TempDir(), "file::memory:?cache=shared") privateKey, err := crypto.GenerateKey() require.NoError(t, err) auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(1337)) @@ -175,7 +175,7 @@ func TestStressAndReorgs(t *testing.T) { ) ctx := context.Background() - dbPathSyncer := path.Join(t.TempDir(), "tmp.sqlite") + dbPathSyncer := path.Join(t.TempDir(), "file::memory:?cache=shared") dbPathReorg := t.TempDir() privateKey, err := crypto.GenerateKey() require.NoError(t, err) diff --git a/test/helpers/aggoracle_e2e.go b/test/helpers/aggoracle_e2e.go index 0c1cc1f4..97f97875 100644 --- a/test/helpers/aggoracle_e2e.go +++ b/test/helpers/aggoracle_e2e.go @@ -105,7 +105,7 @@ func CommonSetup(t *testing.T) ( reorg, err := reorgdetector.New(l1Client.Client(), reorgdetector.Config{DBPath: dbPathReorgDetector}) require.NoError(t, err) // Syncer - dbPathSyncer := path.Join(t.TempDir(), "tmp.sqlite") + dbPathSyncer := path.Join(t.TempDir(), "file::memory:?cache=shared") syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerL1Addr, common.Address{}, 10, etherman.LatestBlock, reorg, l1Client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3) require.NoError(t, err) go syncer.Start(ctx) diff --git a/tree/tree_test.go b/tree/tree_test.go index d77785c1..201d21e5 100644 --- a/tree/tree_test.go +++ b/tree/tree_test.go @@ -29,12 +29,14 @@ func TestMTAddLeaf(t *testing.T) { for ti, testVector := range mtTestVectors { t.Run(fmt.Sprintf("Test vector %d", ti), func(t *testing.T) { - dbPath := path.Join(t.TempDir(), "tmp.db") + dbPath := path.Join(t.TempDir(), "file::memory:?cache=shared") log.Debug("DB created at: ", dbPath) err := migrations.RunMigrations(dbPath) require.NoError(t, err) db, err := db.NewSQLiteDB(dbPath) require.NoError(t, err) + _, err = db.Exec(`select * from root`) + require.NoError(t, err) merkletree := tree.NewAppendOnlyTree(db, "") // Add exisiting leaves @@ -82,7 +84,7 @@ func TestMTGetProof(t *testing.T) { for ti, testVector := range mtTestVectors { t.Run(fmt.Sprintf("Test vector %d", ti), func(t *testing.T) { - dbPath := path.Join(t.TempDir(), "tmp.db") + dbPath := path.Join(t.TempDir(), "file::memory:?cache=shared") err := migrations.RunMigrations(dbPath) require.NoError(t, err) db, err := db.NewSQLiteDB(dbPath) From 9842ad5336eb86a9353e3602737beb82133e8845 Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 5 Sep 2024 14:22:07 +0200 Subject: [PATCH 20/31] increase timestamp to pass UT --- l1infotreesync/processor.go | 14 ++++++++------ lastgersync/e2e_test.go | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index d5b8b053..6d9dd649 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -5,6 +5,7 @@ import ( "database/sql" "encoding/binary" "errors" + "fmt" "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/l1infotreesync/migrations" @@ -240,7 +241,7 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { }() if _, err := tx.Exec(`INSERT INTO block (num) VALUES ($1)`, b.Num); err != nil { - return err + return fmt.Errorf("err: %w", err) } var initialL1InfoIndex uint32 @@ -248,8 +249,9 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { lastIndex, err := p.getLastIndex(tx) if err == ErrNotFound { initialL1InfoIndex = 0 + err = nil } else if err != nil { - return err + return fmt.Errorf("err: %w", err) } else { initialL1InfoIndex = lastIndex + 1 } @@ -270,14 +272,14 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { info.Hash = info.hash() err = meddler.Insert(tx, "l1info_leaf", info) if err != nil { - return err + return fmt.Errorf("err: %w", err) } err = p.l1InfoTree.AddLeaf(tx, info.BlockNumber, info.BlockPosition, treeTypes.Leaf{ Index: info.L1InfoTreeIndex, Hash: info.Hash, }) if err != nil { - return err + return fmt.Errorf("err: %w", err) } l1InfoLeavesAdded++ } @@ -288,7 +290,7 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { Hash: event.VerifyBatches.ExitRoot, }) if err != nil { - return err + return fmt.Errorf("err: %w", err) } } @@ -300,7 +302,7 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { } if err := tx.Commit(); err != nil { - return err + return fmt.Errorf("err: %w", err) } log.Infof("block %d processed with %d events", b.Num, len(b.Events)) return nil diff --git a/lastgersync/e2e_test.go b/lastgersync/e2e_test.go index 888f4b84..b851600b 100644 --- a/lastgersync/e2e_test.go +++ b/lastgersync/e2e_test.go @@ -40,7 +40,7 @@ func TestE2E(t *testing.T) { _, err := env.GERL1Contract.UpdateExitRoot(env.AuthL1, common.HexToHash(strconv.Itoa(i))) require.NoError(t, err) env.L1Client.Commit() - time.Sleep(time.Millisecond * 50) + time.Sleep(time.Millisecond * 150) expectedGER, err := env.GERL1Contract.GetLastGlobalExitRoot(&bind.CallOpts{Pending: false}) require.NoError(t, err) isInjected, err := env.AggOracleSender.IsGERAlreadyInjected(expectedGER) From a2122336d7f734807a48390081be86a822624555 Mon Sep 17 00:00:00 2001 From: Arnau Date: Mon, 9 Sep 2024 09:49:27 +0200 Subject: [PATCH 21/31] review --- bridgesync/e2e_test.go | 2 +- bridgesync/processor.go | 17 ++----- db/interface.go | 9 ++++ db/meddler.go | 44 ++++++++++++----- db/migrations.go | 2 +- db/sqlite.go | 4 +- go.mod | 1 + go.sum | 4 +- l1infotreesync/migrations/migrations.go | 7 +-- l1infotreesync/processor.go | 20 ++------ tree/appendonlytree.go | 4 +- tree/tree.go | 63 +++++++------------------ 12 files changed, 78 insertions(+), 99 deletions(-) create mode 100644 db/interface.go diff --git a/bridgesync/e2e_test.go b/bridgesync/e2e_test.go index 9f0d2d7e..c6616dbe 100644 --- a/bridgesync/e2e_test.go +++ b/bridgesync/e2e_test.go @@ -71,7 +71,7 @@ func TestBridgeEventE2E(t *testing.T) { DepositCount: uint32(i), DestinationNetwork: 3, DestinationAddress: common.HexToAddress("f00"), - Metadata: nil, + Metadata: []byte{}, } tx, err := bridgeSc.BridgeAsset( auth, diff --git a/bridgesync/processor.go b/bridgesync/processor.go index 5de3359e..013354b3 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -124,8 +124,7 @@ func (p *processor) GetBridges( } defer tx.Rollback() - err = p.isBlockProcessed(tx, toBlock) - if err != nil { + if err = p.isBlockProcessed(tx, toBlock); err != nil { return nil, err } @@ -149,8 +148,7 @@ func (p *processor) GetClaims( } defer tx.Rollback() - err = p.isBlockProcessed(tx, toBlock) - if err != nil { + if err = p.isBlockProcessed(tx, toBlock); err != nil { return nil, err } @@ -165,7 +163,7 @@ func (p *processor) GetClaims( return db.SlicePtrsToSlice(claims).([]Claim), err } -func (p *processor) isBlockProcessed(tx *sql.Tx, blockNum uint64) error { +func (p *processor) isBlockProcessed(tx db.DBer, blockNum uint64) error { lpb, err := p.getLastProcessedBlockWithTx(tx) if err != nil { return err @@ -179,15 +177,10 @@ func (p *processor) isBlockProcessed(tx *sql.Tx, blockNum uint64) error { // GetLastProcessedBlock returns the last processed block by the processor, including blocks // that don't have events func (p *processor) GetLastProcessedBlock(ctx context.Context) (uint64, error) { - tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) - if err != nil { - return 0, err - } - defer tx.Rollback() - return p.getLastProcessedBlockWithTx(tx) + return p.getLastProcessedBlockWithTx(p.db) } -func (p *processor) getLastProcessedBlockWithTx(tx *sql.Tx) (uint64, error) { +func (p *processor) getLastProcessedBlockWithTx(tx db.DBer) (uint64, error) { var lastProcessedBlock uint64 row := tx.QueryRow("SELECT num FROM BLOCK ORDER BY num DESC LIMIT 1;") err := row.Scan(&lastProcessedBlock) diff --git a/db/interface.go b/db/interface.go new file mode 100644 index 00000000..acf73ca3 --- /dev/null +++ b/db/interface.go @@ -0,0 +1,9 @@ +package db + +import "database/sql" + +type DBer interface { + Exec(query string, args ...interface{}) (sql.Result, error) + Query(query string, args ...interface{}) (*sql.Rows, error) + QueryRow(query string, args ...interface{}) *sql.Row +} diff --git a/db/meddler.go b/db/meddler.go index aa5f992c..41527526 100644 --- a/db/meddler.go +++ b/db/meddler.go @@ -1,6 +1,7 @@ package db import ( + "errors" "fmt" "math/big" "reflect" @@ -8,8 +9,8 @@ import ( tree "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" + sqlite "github.com/mattn/go-sqlite3" "github.com/russross/meddler" - "modernc.org/sqlite" ) // initMeddler registers tags to be used to read/write from SQL DBs using meddler @@ -20,16 +21,16 @@ func initMeddler() { meddler.Register("hash", HashMeddler{}) } -func SQLiteErr(err error) (*sqlite.Error, bool) { - if sqliteErr, ok := err.(*sqlite.Error); ok { +func SQLiteErr(err error) (sqlite.Error, bool) { + if sqliteErr, ok := err.(sqlite.Error); ok { return sqliteErr, true } if driverErr, ok := meddler.DriverErr(err); ok { - if sqliteErr, ok := driverErr.(*sqlite.Error); ok { + if sqliteErr, ok := driverErr.(sqlite.Error); ok { return sqliteErr, true } } - return nil, false + return sqlite.Error{}, false } // SliceToSlicePtrs converts any []Foo to []*Foo @@ -71,8 +72,10 @@ func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error { if ptr == nil { return fmt.Errorf("BigIntMeddler.PostRead: nil pointer") } - field := fieldPtr.(**big.Int) - var ok bool + field, ok := fieldPtr.(**big.Int) + if !ok { + return errors.New("fieldPtr is not *big.Int") + } *field, ok = new(big.Int).SetString(*ptr, 10) if !ok { return fmt.Errorf("big.Int.SetString failed on \"%v\"", *ptr) @@ -82,7 +85,10 @@ func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error { // PreWrite is called before an Insert or Update operation for fields that have the BigIntMeddler func (b BigIntMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) { - field := fieldPtr.(*big.Int) + field, ok := fieldPtr.(*big.Int) + if !ok { + return nil, errors.New("fieldPtr is not *big.Int") + } return field.String(), nil } @@ -100,9 +106,12 @@ func (b MerkleProofMeddler) PreRead(fieldAddr interface{}) (scanTarget interface func (b MerkleProofMeddler) PostRead(fieldPtr, scanTarget interface{}) error { ptr := scanTarget.(*string) if ptr == nil { - return fmt.Errorf("ProofMeddler.PostRead: nil pointer") + return errors.New("ProofMeddler.PostRead: nil pointer") + } + field, ok := fieldPtr.(*tree.Proof) + if !ok { + return errors.New("fieldPtr is not tree.Proof") } - field := fieldPtr.(*tree.Proof) strHashes := strings.Split(*ptr, ",") if len(strHashes) != int(tree.DefaultHeight) { return fmt.Errorf("unexpected len of hashes: expected %d actual %d", tree.DefaultHeight, len(strHashes)) @@ -115,7 +124,10 @@ func (b MerkleProofMeddler) PostRead(fieldPtr, scanTarget interface{}) error { // PreWrite is called before an Insert or Update operation for fields that have the ProofMeddler func (b MerkleProofMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) { - field := fieldPtr.(tree.Proof) + field, ok := fieldPtr.(tree.Proof) + if !ok { + return nil, errors.New("fieldPtr is not tree.Proof") + } var s string for _, f := range field { s += f.Hex() + "," @@ -139,13 +151,19 @@ func (b HashMeddler) PostRead(fieldPtr, scanTarget interface{}) error { if ptr == nil { return fmt.Errorf("HashMeddler.PostRead: nil pointer") } - field := fieldPtr.(*common.Hash) + field, ok := fieldPtr.(*common.Hash) + if !ok { + return errors.New("fieldPtr is not common.Hash") + } *field = common.HexToHash(*ptr) return nil } // PreWrite is called before an Insert or Update operation for fields that have the ProofMeddler func (b HashMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) { - field := fieldPtr.(common.Hash) + field, ok := fieldPtr.(common.Hash) + if !ok { + return nil, errors.New("fieldPtr is not common.Hash") + } return field.Hex(), nil } diff --git a/db/migrations.go b/db/migrations.go index 4fa1cca5..07315375 100644 --- a/db/migrations.go +++ b/db/migrations.go @@ -4,8 +4,8 @@ import ( "fmt" "github.com/0xPolygon/cdk/log" + _ "github.com/mattn/go-sqlite3" migrate "github.com/rubenv/sql-migrate" - _ "modernc.org/sqlite" ) // RunMigrations will execute pending migrations if needed to keep diff --git a/db/sqlite.go b/db/sqlite.go index 85a86430..ef5ad9e7 100644 --- a/db/sqlite.go +++ b/db/sqlite.go @@ -3,13 +3,13 @@ package db import ( "database/sql" - _ "modernc.org/sqlite" + _ "github.com/mattn/go-sqlite3" ) // NewSQLiteDB creates a new SQLite DB func NewSQLiteDB(dbPath string) (*sql.DB, error) { initMeddler() - db, err := sql.Open("sqlite", dbPath) + db, err := sql.Open("sqlite3", dbPath) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index b489c734..f64ec3bb 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/jackc/pgconn v1.14.3 github.com/jackc/pgx/v4 v4.18.3 github.com/ledgerwatch/erigon-lib v1.0.0 + github.com/mattn/go-sqlite3 v1.14.23 github.com/mitchellh/mapstructure v1.5.0 github.com/rubenv/sql-migrate v1.6.1 github.com/russross/meddler v1.0.1 diff --git a/go.sum b/go.sum index e2888e50..bc9eb188 100644 --- a/go.sum +++ b/go.sum @@ -303,8 +303,8 @@ github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4 github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI= -github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0= +github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/miguelmota/go-solidity-sha3 v0.1.1 h1:3Y08sKZDtudtE5kbTBPC9RYJznoSYyWI9VD6mghU0CA= github.com/miguelmota/go-solidity-sha3 v0.1.1/go.mod h1:sax1FvQF+f71j8W1uUHMZn8NxKyl5rYLks2nqj8RFEw= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= diff --git a/l1infotreesync/migrations/migrations.go b/l1infotreesync/migrations/migrations.go index 28fb2389..6823a2cf 100644 --- a/l1infotreesync/migrations/migrations.go +++ b/l1infotreesync/migrations/migrations.go @@ -32,11 +32,8 @@ var Migrations = &migrate.MemoryMigrationSource{ } func RunMigrations(dbPath string) error { - migs := []*migrate.Migration{} - retMigs := treeMigrations.MigrationsWithPrefix(RollupExitTreePrefix) - migs = append(migs, retMigs...) - l1InfoMigs := treeMigrations.MigrationsWithPrefix(L1InfoTreePrefix) - migs = append(migs, l1InfoMigs...) + migs := treeMigrations.MigrationsWithPrefix(RollupExitTreePrefix) + migs = append(migs, treeMigrations.MigrationsWithPrefix(L1InfoTreePrefix)...) migs = append(migs, Migrations.Migrations...) for _, m := range migs { log.Debugf("%+v", m.Id) diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index 6d9dd649..7b56a7de 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -155,15 +155,10 @@ func (p *processor) GetLatestInfoUntilBlock(ctx context.Context, blockNum uint64 // GetInfoByIndex returns the value of a leaf (not the hash) of the L1 info tree func (p *processor) GetInfoByIndex(ctx context.Context, index uint32) (*L1InfoTreeLeaf, error) { - tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) - if err != nil { - return nil, err - } - defer tx.Rollback() - return p.getInfoByIndexWithTx(tx, index) + return p.getInfoByIndexWithTx(p.db, index) } -func (p *processor) getInfoByIndexWithTx(tx *sql.Tx, index uint32) (*L1InfoTreeLeaf, error) { +func (p *processor) getInfoByIndexWithTx(tx db.DBer, index uint32) (*L1InfoTreeLeaf, error) { info := &L1InfoTreeLeaf{} return info, meddler.QueryRow( tx, info, @@ -173,15 +168,10 @@ func (p *processor) getInfoByIndexWithTx(tx *sql.Tx, index uint32) (*L1InfoTreeL // GetLastProcessedBlock returns the last processed block func (p *processor) GetLastProcessedBlock(ctx context.Context) (uint64, error) { - tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) - if err != nil { - return 0, err - } - defer tx.Rollback() - return p.getLastProcessedBlockWithTx(tx) + return p.getLastProcessedBlockWithTx(p.db) } -func (p *processor) getLastProcessedBlockWithTx(tx *sql.Tx) (uint64, error) { +func (p *processor) getLastProcessedBlockWithTx(tx db.DBer) (uint64, error) { var lastProcessedBlock uint64 row := tx.QueryRow("SELECT num FROM BLOCK ORDER BY num DESC LIMIT 1;") err := row.Scan(&lastProcessedBlock) @@ -308,7 +298,7 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { return nil } -func (p *processor) getLastIndex(tx *sql.Tx) (uint32, error) { +func (p *processor) getLastIndex(tx db.DBer) (uint32, error) { var lastProcessedIndex uint32 row := tx.QueryRow("SELECT position FROM l1info_leaf ORDER BY block_num DESC, block_pos DESC LIMIT 1;") err := row.Scan(&lastProcessedIndex) diff --git a/tree/appendonlytree.go b/tree/appendonlytree.go index 14ec3bc7..195b150f 100644 --- a/tree/appendonlytree.go +++ b/tree/appendonlytree.go @@ -19,7 +19,9 @@ type AppendOnlyTree struct { func NewAppendOnlyTree(db *sql.DB, dbPrefix string) *AppendOnlyTree { t := newTree(db, dbPrefix) return &AppendOnlyTree{ - Tree: t, + Tree: t, + // -1 is used to indicate no leafs, 0 means the first leaf is added (at index 0) and so on. + // In order to differentiate the "cache not initialised" we need any value smaller than -1 lastIndex: -2, } } diff --git a/tree/tree.go b/tree/tree.go index 991faf72..bbcf5a17 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/russross/meddler" "golang.org/x/crypto/sha3" - sqlite3 "modernc.org/sqlite/lib" ) var ( @@ -50,7 +49,7 @@ func newTree(db *sql.DB, tablePrefix string) *Tree { return t } -func (t *Tree) getSiblings(tx *sql.Tx, index uint32, root common.Hash) ( +func (t *Tree) getSiblings(tx db.DBer, index uint32, root common.Hash) ( siblings [32]common.Hash, hasUsedZeroHashes bool, err error, @@ -109,12 +108,7 @@ func (t *Tree) getSiblings(tx *sql.Tx, index uint32, root common.Hash) ( // GetProof returns the merkle proof for a given index and root. func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) (types.Proof, error) { - tx, err := t.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) - if err != nil { - return types.Proof{}, err - } - defer tx.Rollback() - siblings, isErrNotFound, err := t.getSiblings(tx, index, root) + siblings, isErrNotFound, err := t.getSiblings(t.db, index, root) if err != nil { return types.Proof{}, err } @@ -124,7 +118,7 @@ func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) (ty return siblings, nil } -func (t *Tree) getRHTNode(tx *sql.Tx, nodeHash common.Hash) (*types.TreeNode, error) { +func (t *Tree) getRHTNode(tx db.DBer, nodeHash common.Hash) (*types.TreeNode, error) { node := &types.TreeNode{} err := meddler.QueryRow( tx, node, @@ -157,11 +151,11 @@ func generateZeroHashes(height uint8) []common.Hash { return zeroHashes } -func (t *Tree) storeNodes(tx *sql.Tx, nodes []types.TreeNode) error { +func (t *Tree) storeNodes(tx db.DBer, nodes []types.TreeNode) error { for _, node := range nodes { if err := meddler.Insert(tx, t.rhtTable, &node); err != nil { if sqliteErr, ok := db.SQLiteErr(err); ok { - if sqliteErr.Code() == sqlite3.SQLITE_CONSTRAINT_PRIMARYKEY { + if sqliteErr.ExtendedCode == 1555 { // 1555 is the error code for primary key violation // ignore repeated entries. This is likely to happen due to not // cleaning RHT when reorg continue @@ -173,21 +167,16 @@ func (t *Tree) storeNodes(tx *sql.Tx, nodes []types.TreeNode) error { return nil } -func (t *Tree) storeRoot(tx *sql.Tx, root types.Root) error { +func (t *Tree) storeRoot(tx db.DBer, root types.Root) error { return meddler.Insert(tx, t.rootTable, &root) } // GetLastRoot returns the last processed root func (t *Tree) GetLastRoot(ctx context.Context) (types.Root, error) { - tx, err := t.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) - if err != nil { - return types.Root{}, err - } - defer tx.Rollback() - return t.getLastRootWithTx(tx) + return t.getLastRootWithTx(t.db) } -func (t *Tree) getLastRootWithTx(tx *sql.Tx) (types.Root, error) { +func (t *Tree) getLastRootWithTx(tx db.DBer) (types.Root, error) { var root types.Root err := meddler.QueryRow( tx, &root, @@ -204,19 +193,12 @@ func (t *Tree) getLastRootWithTx(tx *sql.Tx) (types.Root, error) { // GetRootByIndex returns the root associated to the index func (t *Tree) GetRootByIndex(ctx context.Context, index uint32) (types.Root, error) { - tx, err := t.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) - if err != nil { - return types.Root{}, err - } - defer tx.Rollback() - var root types.Root - err = meddler.QueryRow( - tx, &root, + if err := meddler.QueryRow( + t.db, &root, fmt.Sprintf(`SELECT * FROM %s WHERE position = $1;`, t.rootTable), index, - ) - if err != nil { + ); err != nil { if errors.Is(err, sql.ErrNoRows) { return root, ErrNotFound } @@ -227,19 +209,12 @@ func (t *Tree) GetRootByIndex(ctx context.Context, index uint32) (types.Root, er // GetRootByHash returns the root associated to the hash func (t *Tree) GetRootByHash(ctx context.Context, hash common.Hash) (types.Root, error) { - tx, err := t.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) - if err != nil { - return types.Root{}, err - } - defer tx.Rollback() - var root types.Root - err = meddler.QueryRow( - tx, &root, + if err := meddler.QueryRow( + t.db, &root, fmt.Sprintf(`SELECT * FROM %s WHERE hash = $1;`, t.rootTable), hash.Hex(), - ) - if err != nil { + ); err != nil { if errors.Is(err, sql.ErrNoRows) { return root, ErrNotFound } @@ -249,15 +224,9 @@ func (t *Tree) GetRootByHash(ctx context.Context, hash common.Hash) (types.Root, } func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (common.Hash, error) { - tx, err := t.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) - if err != nil { - return common.Hash{}, err - } - defer tx.Rollback() - currentNodeHash := root for h := int(types.DefaultHeight - 1); h >= 0; h-- { - currentNode, err := t.getRHTNode(tx, currentNodeHash) + currentNode, err := t.getRHTNode(t.db, currentNodeHash) if err != nil { return common.Hash{}, err } @@ -272,7 +241,7 @@ func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (com } // Reorg deletes all the data relevant from firstReorgedBlock (includded) and onwards -func (t *Tree) Reorg(tx *sql.Tx, firstReorgedBlock uint64) error { +func (t *Tree) Reorg(tx db.DBer, firstReorgedBlock uint64) error { _, err := tx.Exec( fmt.Sprintf(`DELETE FROM %s WHERE block_num >= $1`, t.rootTable), firstReorgedBlock, From d17db59456cf5f976e5dc68214deb890bbc399e0 Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 12 Sep 2024 12:24:59 +0200 Subject: [PATCH 22/31] add callbacks on db tx --- bridgesync/processor.go | 4 +-- db/tx.go | 49 +++++++++++++++++++++++++++++++++++++ l1infotreesync/processor.go | 4 +-- tree/appendonlytree.go | 6 +++-- tree/tree.go | 6 ++--- tree/tree_test.go | 16 ++++++------ tree/updatabletree.go | 3 ++- 7 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 db/tx.go diff --git a/bridgesync/processor.go b/bridgesync/processor.go index 013354b3..807c97d1 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -193,7 +193,7 @@ func (p *processor) getLastProcessedBlockWithTx(tx db.DBer) (uint64, error) { // Reorg triggers a purge and reset process on the processor to leaf it on a state // as if the last block processed was firstReorgedBlock-1 func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { - tx, err := p.db.BeginTx(ctx, nil) + tx, err := db.NewTx(ctx, p.db) if err != nil { return err } @@ -222,7 +222,7 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { // ProcessBlock process the events of the block to build the exit tree // and updates the last processed block (can be called without events for that purpose) func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { - tx, err := p.db.BeginTx(ctx, nil) + tx, err := db.NewTx(ctx, p.db) if err != nil { return err } diff --git a/db/tx.go b/db/tx.go new file mode 100644 index 00000000..dc22750e --- /dev/null +++ b/db/tx.go @@ -0,0 +1,49 @@ +package db + +import ( + "context" + "database/sql" +) + +type Tx struct { + *sql.Tx + rollbackCallbacks []func() + commitCallbacks []func() +} + +func NewTx(ctx context.Context, db *sql.DB) (*Tx, error) { + tx, err := db.BeginTx(ctx, nil) + if err != nil { + return nil, err + } + return &Tx{ + Tx: tx, + }, nil +} + +func (s *Tx) AddRollbackCallback(cb func()) { + s.rollbackCallbacks = append(s.rollbackCallbacks, cb) +} +func (s *Tx) AddCommitCallback(cb func()) { + s.commitCallbacks = append(s.commitCallbacks, cb) +} + +func (s *Tx) Commit() error { + if err := s.Tx.Commit(); err != nil { + return err + } + for _, cb := range s.commitCallbacks { + cb() + } + return nil +} + +func (s *Tx) Rollback() error { + if err := s.Tx.Rollback(); err != nil { + return err + } + for _, cb := range s.rollbackCallbacks { + cb() + } + return nil +} diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index 7b56a7de..467199ae 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -184,7 +184,7 @@ func (p *processor) getLastProcessedBlockWithTx(tx db.DBer) (uint64, error) { // Reorg triggers a purge and reset process on the processor to leaf it on a state // as if the last block processed was firstReorgedBlock-1 func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { - tx, err := p.db.BeginTx(ctx, nil) + tx, err := db.NewTx(ctx, p.db) if err != nil { return err } @@ -218,7 +218,7 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error { // ProcessBlock process the events of the block to build the rollup exit tree and the l1 info tree // and updates the last processed block (can be called without events for that purpose) func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { - tx, err := p.db.BeginTx(ctx, nil) + tx, err := db.NewTx(ctx, p.db) if err != nil { return err } diff --git a/tree/appendonlytree.go b/tree/appendonlytree.go index 195b150f..575240c7 100644 --- a/tree/appendonlytree.go +++ b/tree/appendonlytree.go @@ -4,6 +4,7 @@ import ( "database/sql" "fmt" + "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" ) @@ -26,7 +27,7 @@ func NewAppendOnlyTree(db *sql.DB, dbPrefix string) *AppendOnlyTree { } } -func (t *AppendOnlyTree) AddLeaf(tx *sql.Tx, blockNum, blockPosition uint64, leaf types.Leaf) error { +func (t *AppendOnlyTree) AddLeaf(tx *db.Tx, blockNum, blockPosition uint64, leaf types.Leaf) error { if int64(leaf.Index) != t.lastIndex+1 { // rebuild cache if err := t.initCache(tx); err != nil { @@ -72,10 +73,11 @@ func (t *AppendOnlyTree) AddLeaf(tx *sql.Tx, blockNum, blockPosition uint64, lea return err } t.lastIndex++ + tx.AddRollbackCallback(func() { t.lastIndex-- }) return nil } -func (t *AppendOnlyTree) initCache(tx *sql.Tx) error { +func (t *AppendOnlyTree) initCache(tx *db.Tx) error { siblings := [types.DefaultHeight]common.Hash{} lastRoot, err := t.getLastRootWithTx(tx) if err != nil { diff --git a/tree/tree.go b/tree/tree.go index bbcf5a17..6af507fa 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -151,7 +151,7 @@ func generateZeroHashes(height uint8) []common.Hash { return zeroHashes } -func (t *Tree) storeNodes(tx db.DBer, nodes []types.TreeNode) error { +func (t *Tree) storeNodes(tx *db.Tx, nodes []types.TreeNode) error { for _, node := range nodes { if err := meddler.Insert(tx, t.rhtTable, &node); err != nil { if sqliteErr, ok := db.SQLiteErr(err); ok { @@ -167,7 +167,7 @@ func (t *Tree) storeNodes(tx db.DBer, nodes []types.TreeNode) error { return nil } -func (t *Tree) storeRoot(tx db.DBer, root types.Root) error { +func (t *Tree) storeRoot(tx *db.Tx, root types.Root) error { return meddler.Insert(tx, t.rootTable, &root) } @@ -241,7 +241,7 @@ func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (com } // Reorg deletes all the data relevant from firstReorgedBlock (includded) and onwards -func (t *Tree) Reorg(tx db.DBer, firstReorgedBlock uint64) error { +func (t *Tree) Reorg(tx *db.Tx, firstReorgedBlock uint64) error { _, err := tx.Exec( fmt.Sprintf(`DELETE FROM %s WHERE block_num >= $1`, t.rootTable), firstReorgedBlock, diff --git a/tree/tree_test.go b/tree/tree_test.go index 201d21e5..b5278723 100644 --- a/tree/tree_test.go +++ b/tree/tree_test.go @@ -33,14 +33,14 @@ func TestMTAddLeaf(t *testing.T) { log.Debug("DB created at: ", dbPath) err := migrations.RunMigrations(dbPath) require.NoError(t, err) - db, err := db.NewSQLiteDB(dbPath) + treeDB, err := db.NewSQLiteDB(dbPath) require.NoError(t, err) - _, err = db.Exec(`select * from root`) + _, err = treeDB.Exec(`select * from root`) require.NoError(t, err) - merkletree := tree.NewAppendOnlyTree(db, "") + merkletree := tree.NewAppendOnlyTree(treeDB, "") // Add exisiting leaves - tx, err := db.BeginTx(ctx, nil) + tx, err := db.NewTx(ctx, treeDB) require.NoError(t, err) for i, leaf := range testVector.ExistingLeaves { err = merkletree.AddLeaf(tx, uint64(i), 0, types.Leaf{ @@ -57,7 +57,7 @@ func TestMTAddLeaf(t *testing.T) { } // Add new bridge - tx, err = db.BeginTx(ctx, nil) + tx, err = db.NewTx(ctx, treeDB) require.NoError(t, err) err = merkletree.AddLeaf(tx, uint64(len(testVector.ExistingLeaves)), 0, types.Leaf{ Index: uint32(len(testVector.ExistingLeaves)), @@ -87,11 +87,11 @@ func TestMTGetProof(t *testing.T) { dbPath := path.Join(t.TempDir(), "file::memory:?cache=shared") err := migrations.RunMigrations(dbPath) require.NoError(t, err) - db, err := db.NewSQLiteDB(dbPath) + treeDB, err := db.NewSQLiteDB(dbPath) require.NoError(t, err) - tre := tree.NewAppendOnlyTree(db, "") + tre := tree.NewAppendOnlyTree(treeDB, "") - tx, err := db.BeginTx(ctx, nil) + tx, err := db.NewTx(ctx, treeDB) require.NoError(t, err) for li, leaf := range testVector.Deposits { err = tre.AddLeaf(tx, uint64(li), 0, types.Leaf{ diff --git a/tree/updatabletree.go b/tree/updatabletree.go index 1f85c36a..7bd901f3 100644 --- a/tree/updatabletree.go +++ b/tree/updatabletree.go @@ -3,6 +3,7 @@ package tree import ( "database/sql" + "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" ) @@ -21,7 +22,7 @@ func NewUpdatableTree(db *sql.DB, dbPrefix string) *UpdatableTree { return ut } -func (t *UpdatableTree) UpsertLeaf(tx *sql.Tx, blockNum, blockPosition uint64, leaf types.Leaf) error { +func (t *UpdatableTree) UpsertLeaf(tx *db.Tx, blockNum, blockPosition uint64, leaf types.Leaf) error { var rootHash common.Hash root, err := t.getLastRootWithTx(tx) if err != nil { From 3d5a2ab587a5c99bcd9927153518bc522a1e09bf Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 12 Sep 2024 15:03:54 +0200 Subject: [PATCH 23/31] lint --- bridgesync/processor.go | 13 ++++++++++--- bridgesync/processor_test.go | 12 ++++++------ db/meddler.go | 29 +++++++++++++++++++---------- l1infotreesync/processor.go | 6 +++++- lastgersync/evmdownloader.go | 4 ++-- test/helpers/aggoracle_e2e.go | 4 +++- tree/appendonlytree.go | 5 +++-- tree/tree.go | 8 +++++--- tree/updatabletree.go | 3 ++- 9 files changed, 55 insertions(+), 29 deletions(-) diff --git a/bridgesync/processor.go b/bridgesync/processor.go index 80ce479a..53d1b044 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -124,8 +124,11 @@ func (p *processor) GetBridges( if err != nil { return nil, err } - - defer tx.Rollback() + defer func() { + if err := tx.Rollback(); err != nil { + log.Warnf("error rolling back tx: %v", err) + } + }() if err = p.isBlockProcessed(tx, toBlock); err != nil { return nil, err @@ -149,7 +152,11 @@ func (p *processor) GetClaims( if err != nil { return nil, err } - defer tx.Rollback() + defer func() { + if err := tx.Rollback(); err != nil { + log.Warnf("error rolling back tx: %v", err) + } + }() if err = p.isBlockProcessed(tx, toBlock); err != nil { return nil, err diff --git a/bridgesync/processor_test.go b/bridgesync/processor_test.go index 71ad5b46..fd16f32c 100644 --- a/bridgesync/processor_test.go +++ b/bridgesync/processor_test.go @@ -397,7 +397,7 @@ var ( type processAction interface { method() string desc() string - execute(t *testing.T) + execute(t *testing.T) //nolint:thelper } // GetClaims @@ -420,7 +420,7 @@ func (a *getClaims) desc() string { return a.description } -func (a *getClaims) execute(t *testing.T) { +func (a *getClaims) execute(t *testing.T) { //nolint:thelper actualEvents, actualErr := a.p.GetClaims(a.ctx, a.fromBlock, a.toBlock) require.Equal(t, a.expectedClaims, actualEvents) require.Equal(t, a.expectedErr, actualErr) @@ -446,7 +446,7 @@ func (a *getBridges) desc() string { return a.description } -func (a *getBridges) execute(t *testing.T) { +func (a *getBridges) execute(t *testing.T) { //nolint:thelper actualEvents, actualErr := a.p.GetBridges(a.ctx, a.fromBlock, a.toBlock) require.Equal(t, a.expectedBridges, actualEvents) require.Equal(t, a.expectedErr, actualErr) @@ -470,7 +470,7 @@ func (a *getLastProcessedBlockAction) desc() string { return a.description } -func (a *getLastProcessedBlockAction) execute(t *testing.T) { +func (a *getLastProcessedBlockAction) execute(t *testing.T) { //nolint:thelper t.Helper() actualLastProcessedBlock, actualErr := a.p.GetLastProcessedBlock(a.ctx) @@ -495,7 +495,7 @@ func (a *reorgAction) desc() string { return a.description } -func (a *reorgAction) execute(t *testing.T) { +func (a *reorgAction) execute(t *testing.T) { //nolint:thelper t.Helper() actualErr := a.p.Reorg(context.Background(), a.firstReorgedBlock) @@ -519,7 +519,7 @@ func (a *processBlockAction) desc() string { return a.description } -func (a *processBlockAction) execute(t *testing.T) { +func (a *processBlockAction) execute(t *testing.T) { //nolint:thelper t.Helper() actualErr := a.p.ProcessBlock(context.Background(), a.block) diff --git a/db/meddler.go b/db/meddler.go index 41527526..90071916 100644 --- a/db/meddler.go +++ b/db/meddler.go @@ -21,16 +21,15 @@ func initMeddler() { meddler.Register("hash", HashMeddler{}) } -func SQLiteErr(err error) (sqlite.Error, bool) { - if sqliteErr, ok := err.(sqlite.Error); ok { +func SQLiteErr(err error) (*sqlite.Error, bool) { + sqliteErr := &sqlite.Error{} + if ok := errors.As(err, sqliteErr); ok { return sqliteErr, true } if driverErr, ok := meddler.DriverErr(err); ok { - if sqliteErr, ok := driverErr.(sqlite.Error); ok { - return sqliteErr, true - } + return sqliteErr, errors.As(driverErr, sqliteErr) } - return sqlite.Error{}, false + return sqliteErr, false } // SliceToSlicePtrs converts any []Foo to []*Foo @@ -68,7 +67,10 @@ func (b BigIntMeddler) PreRead(fieldAddr interface{}) (scanTarget interface{}, e // PostRead is called after a Scan operation for fields that have the BigIntMeddler func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error { - ptr := scanTarget.(*string) + ptr, ok := scanTarget.(*string) + if !ok { + return errors.New("scanTarget is not *string") + } if ptr == nil { return fmt.Errorf("BigIntMeddler.PostRead: nil pointer") } @@ -76,7 +78,8 @@ func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error { if !ok { return errors.New("fieldPtr is not *big.Int") } - *field, ok = new(big.Int).SetString(*ptr, 10) + decimal := 10 + *field, ok = new(big.Int).SetString(*ptr, decimal) if !ok { return fmt.Errorf("big.Int.SetString failed on \"%v\"", *ptr) } @@ -104,7 +107,10 @@ func (b MerkleProofMeddler) PreRead(fieldAddr interface{}) (scanTarget interface // PostRead is called after a Scan operation for fields that have the ProofMeddler func (b MerkleProofMeddler) PostRead(fieldPtr, scanTarget interface{}) error { - ptr := scanTarget.(*string) + ptr, ok := scanTarget.(*string) + if !ok { + return errors.New("scanTarget is not *string") + } if ptr == nil { return errors.New("ProofMeddler.PostRead: nil pointer") } @@ -147,7 +153,10 @@ func (b HashMeddler) PreRead(fieldAddr interface{}) (scanTarget interface{}, err // PostRead is called after a Scan operation for fields that have the ProofMeddler func (b HashMeddler) PostRead(fieldPtr, scanTarget interface{}) error { - ptr := scanTarget.(*string) + ptr, ok := scanTarget.(*string) + if !ok { + return errors.New("scanTarget is not *string") + } if ptr == nil { return fmt.Errorf("HashMeddler.PostRead: nil pointer") } diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index 5f946f15..47e5dd5e 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -130,7 +130,11 @@ func (p *processor) GetLatestInfoUntilBlock(ctx context.Context, blockNum uint64 if err != nil { return nil, err } - defer tx.Rollback() + defer func() { + if err := tx.Rollback(); err != nil { + log.Warnf("error rolling back tx: %v", err) + } + }() lpb, err := p.getLastProcessedBlockWithTx(tx) if err != nil { diff --git a/lastgersync/evmdownloader.go b/lastgersync/evmdownloader.go index 9071998f..91e05c7a 100644 --- a/lastgersync/evmdownloader.go +++ b/lastgersync/evmdownloader.go @@ -129,11 +129,11 @@ func (d *downloader) Download(ctx context.Context, fromBlock uint64, downloadedC func (d *downloader) getGERsFromIndex(ctx context.Context, fromL1InfoTreeIndex uint32) ([]Event, error) { lastRoot, err := d.l1InfoTreesync.GetLastL1InfoTreeRoot(ctx) - if err == tree.ErrNotFound { + if errors.Is(err, tree.ErrNotFound) { return nil, nil } if err != nil { - return nil, fmt.Errorf("error calling GetLastL1InfoTreeRoot: %v", err) + return nil, fmt.Errorf("error calling GetLastL1InfoTreeRoot: %w", err) } gers := []Event{} diff --git a/test/helpers/aggoracle_e2e.go b/test/helpers/aggoracle_e2e.go index 3c72d3cc..46b2e6cd 100644 --- a/test/helpers/aggoracle_e2e.go +++ b/test/helpers/aggoracle_e2e.go @@ -113,7 +113,9 @@ func CommonSetup(t *testing.T) ( require.NoError(t, err) // Syncer dbPathSyncer := path.Join(t.TempDir(), "file::memory:?cache=shared") - syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerL1Addr, common.Address{}, 10, etherman.LatestBlock, reorg, l1Client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3) + maxRetries := 3 + syncBlockChunkSize := 10 + syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerL1Addr, common.Address{}, syncBlockChunkSize, etherman.LatestBlock, reorg, l1Client.Client(), time.Millisecond, 0, 100*time.Millisecond, maxRetries) require.NoError(t, err) go syncer.Start(ctx) diff --git a/tree/appendonlytree.go b/tree/appendonlytree.go index 575240c7..d527a819 100644 --- a/tree/appendonlytree.go +++ b/tree/appendonlytree.go @@ -2,6 +2,7 @@ package tree import ( "database/sql" + "errors" "fmt" "github.com/0xPolygon/cdk/db" @@ -81,7 +82,7 @@ func (t *AppendOnlyTree) initCache(tx *db.Tx) error { siblings := [types.DefaultHeight]common.Hash{} lastRoot, err := t.getLastRootWithTx(tx) if err != nil { - if err == ErrNotFound { + if errors.Is(err, ErrNotFound) { t.lastIndex = -1 t.lastLeftCache = siblings return nil @@ -96,7 +97,7 @@ func (t *AppendOnlyTree) initCache(tx *db.Tx) error { currentNode, err := t.getRHTNode(tx, currentNodeHash) if err != nil { return fmt.Errorf( - "error getting node %s from the RHT at height %d with root %s: %v", + "error getting node %s from the RHT at height %d with root %s: %w", currentNodeHash.Hex(), h, lastRoot.Hash.Hex(), err, ) } diff --git a/tree/tree.go b/tree/tree.go index 4cd94991..6d10834b 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -9,6 +9,7 @@ import ( "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" + "github.com/mattn/go-sqlite3" "github.com/russross/meddler" "golang.org/x/crypto/sha3" ) @@ -153,10 +154,11 @@ func generateZeroHashes(height uint8) []common.Hash { } func (t *Tree) storeNodes(tx *db.Tx, nodes []types.TreeNode) error { - for _, node := range nodes { - if err := meddler.Insert(tx, t.rhtTable, &node); err != nil { + for i := 0; i < len(nodes); i++ { + if err := meddler.Insert(tx, t.rhtTable, &nodes[i]); err != nil { if sqliteErr, ok := db.SQLiteErr(err); ok { - if sqliteErr.ExtendedCode == 1555 { // 1555 is the error code for primary key violation + uniqueConstraint := sqlite3.ErrNoExtended(1555) // 1555 is the error code for primary key violation + if sqliteErr.ExtendedCode == uniqueConstraint { // ignore repeated entries. This is likely to happen due to not // cleaning RHT when reorg continue diff --git a/tree/updatabletree.go b/tree/updatabletree.go index 7bd901f3..4e9f753f 100644 --- a/tree/updatabletree.go +++ b/tree/updatabletree.go @@ -2,6 +2,7 @@ package tree import ( "database/sql" + "errors" "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/tree/types" @@ -26,7 +27,7 @@ func (t *UpdatableTree) UpsertLeaf(tx *db.Tx, blockNum, blockPosition uint64, le var rootHash common.Hash root, err := t.getLastRootWithTx(tx) if err != nil { - if err == ErrNotFound { + if errors.Is(err, ErrNotFound) { rootHash = t.zeroHashes[types.DefaultHeight] } else { return err From f541a20b3f340e092925756d00baa654f45594da Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 12 Sep 2024 15:21:03 +0200 Subject: [PATCH 24/31] fix compilation --- test/helpers/aggoracle_e2e.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/helpers/aggoracle_e2e.go b/test/helpers/aggoracle_e2e.go index 46b2e6cd..b43ce5e9 100644 --- a/test/helpers/aggoracle_e2e.go +++ b/test/helpers/aggoracle_e2e.go @@ -114,7 +114,7 @@ func CommonSetup(t *testing.T) ( // Syncer dbPathSyncer := path.Join(t.TempDir(), "file::memory:?cache=shared") maxRetries := 3 - syncBlockChunkSize := 10 + syncBlockChunkSize := uint64(10) syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerL1Addr, common.Address{}, syncBlockChunkSize, etherman.LatestBlock, reorg, l1Client.Client(), time.Millisecond, 0, 100*time.Millisecond, maxRetries) require.NoError(t, err) go syncer.Start(ctx) From 76b5b44bf81d81f7aa61f31037d2e32c01eb57df Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 12 Sep 2024 16:25:18 +0200 Subject: [PATCH 25/31] fix linter II --- bridgesync/migrations/migrations.go | 5 +-- bridgesync/processor.go | 60 ++++++++++++++++------------- bridgesync/processor_test.go | 18 ++++++--- db/sqlite.go | 4 ++ tree/migrations/migrations.go | 4 +- tree/tree.go | 4 +- 6 files changed, 55 insertions(+), 40 deletions(-) diff --git a/bridgesync/migrations/migrations.go b/bridgesync/migrations/migrations.go index b0c611d8..588948b8 100644 --- a/bridgesync/migrations/migrations.go +++ b/bridgesync/migrations/migrations.go @@ -27,9 +27,8 @@ var bridgeMigrations = &migrate.MemoryMigrationSource{ } func RunMigrations(dbPath string) error { - migs := append( + return db.RunMigrations(dbPath, &migrate.MemoryMigrationSource{Migrations: append( bridgeMigrations.Migrations, treeMigrations.Migrations.Migrations..., - ) - return db.RunMigrations(dbPath, &migrate.MemoryMigrationSource{Migrations: migs}) + )}) } diff --git a/bridgesync/processor.go b/bridgesync/processor.go index 53d1b044..942ec9b1 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -120,34 +120,36 @@ func newProcessor(dbPath, loggerPrefix string) (*processor, error) { func (p *processor) GetBridges( ctx context.Context, fromBlock, toBlock uint64, ) ([]Bridge, error) { - tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) + bridgePtrs := []*Bridge{} + bridgesIface, err := p.getTypeFromBlockToBlock(ctx, fromBlock, toBlock, "bridge", bridgePtrs) if err != nil { return nil, err } - defer func() { - if err := tx.Rollback(); err != nil { - log.Warnf("error rolling back tx: %v", err) - } - }() - - if err = p.isBlockProcessed(tx, toBlock); err != nil { - return nil, err - } - - bridges := []*Bridge{} - err = meddler.QueryAll(tx, &bridges, ` - SELECT * FROM bridge - WHERE block_num >= $1 AND block_num <= $2; - `, fromBlock, toBlock) - if errors.Is(err, sql.ErrNoRows) { - return nil, ErrNotFound + bridges, ok := bridgesIface.([]Bridge) + if !ok { + return nil, errors.New("failed to convert from []*Bridge to []Bridge") } - return db.SlicePtrsToSlice(bridges).([]Bridge), err + return bridges, nil } func (p *processor) GetClaims( ctx context.Context, fromBlock, toBlock uint64, ) ([]Claim, error) { + claimPtrs := []*Claim{} + claimsIface, err := p.getTypeFromBlockToBlock(ctx, fromBlock, toBlock, "claim", claimPtrs) + if err != nil { + return nil, err + } + claims, ok := claimsIface.([]Claim) + if !ok { + return nil, errors.New("failed to convert from []*Claim to []Claim") + } + return claims, nil +} + +func (p *processor) getTypeFromBlockToBlock( + ctx context.Context, fromBlock, toBlock uint64, table string, typeToQuery interface{}, +) (interface{}, error) { tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return nil, err @@ -162,15 +164,18 @@ func (p *processor) GetClaims( return nil, err } - claims := []*Claim{} - err = meddler.QueryAll(tx, &claims, ` - SELECT * FROM claim + err = meddler.QueryAll(tx, typeToQuery, ` + SELECT * FROM `+table+` WHERE block_num >= $1 AND block_num <= $2; `, fromBlock, toBlock) - if errors.Is(err, sql.ErrNoRows) { - return nil, ErrNotFound + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrNotFound + } + return nil, err } - return db.SlicePtrsToSlice(claims).([]Claim), err + + return db.SlicePtrsToSlice(typeToQuery), nil } func (p *processor) isBlockProcessed(tx db.DBer, blockNum uint64) error { @@ -249,7 +254,10 @@ func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error { return err } for _, e := range block.Events { - event := e.(Event) + event, ok := e.(Event) + if !ok { + return errors.New("failed to convert sync.Block.Event to Event") + } if event.Bridge != nil { if err = p.exitTree.AddLeaf(tx, block.Num, event.Pos, types.Leaf{ Index: event.Bridge.DepositCount, diff --git a/bridgesync/processor_test.go b/bridgesync/processor_test.go index fd16f32c..5578cee5 100644 --- a/bridgesync/processor_test.go +++ b/bridgesync/processor_test.go @@ -397,7 +397,7 @@ var ( type processAction interface { method() string desc() string - execute(t *testing.T) //nolint:thelper + execute(t *testing.T) } // GetClaims @@ -470,7 +470,7 @@ func (a *getLastProcessedBlockAction) desc() string { return a.description } -func (a *getLastProcessedBlockAction) execute(t *testing.T) { //nolint:thelper +func (a *getLastProcessedBlockAction) execute(t *testing.T) { t.Helper() actualLastProcessedBlock, actualErr := a.p.GetLastProcessedBlock(a.ctx) @@ -495,7 +495,7 @@ func (a *reorgAction) desc() string { return a.description } -func (a *reorgAction) execute(t *testing.T) { //nolint:thelper +func (a *reorgAction) execute(t *testing.T) { t.Helper() actualErr := a.p.Reorg(context.Background(), a.firstReorgedBlock) @@ -519,7 +519,7 @@ func (a *processBlockAction) desc() string { return a.description } -func (a *processBlockAction) execute(t *testing.T) { //nolint:thelper +func (a *processBlockAction) execute(t *testing.T) { t.Helper() actualErr := a.p.ProcessBlock(context.Background(), a.block) @@ -529,7 +529,10 @@ func (a *processBlockAction) execute(t *testing.T) { //nolint:thelper func eventsToBridges(events []interface{}) []Bridge { bridges := []Bridge{} for _, event := range events { - e := event.(Event) + e, ok := event.(Event) + if !ok { + panic("should be ok") + } if e.Bridge != nil { bridges = append(bridges, *e.Bridge) } @@ -540,7 +543,10 @@ func eventsToBridges(events []interface{}) []Bridge { func eventsToClaims(events []interface{}) []Claim { claims := []Claim{} for _, event := range events { - e := event.(Event) + e, ok := event.(Event) + if !ok { + panic("should be ok") + } if e.Claim != nil { claims = append(claims, *e.Claim) } diff --git a/db/sqlite.go b/db/sqlite.go index ef5ad9e7..e30e9e26 100644 --- a/db/sqlite.go +++ b/db/sqlite.go @@ -6,6 +6,10 @@ import ( _ "github.com/mattn/go-sqlite3" ) +const ( + UniqueConstrain = 1555 +) + // NewSQLiteDB creates a new SQLite DB func NewSQLiteDB(dbPath string) (*sql.DB, error) { initMeddler() diff --git a/tree/migrations/migrations.go b/tree/migrations/migrations.go index ffdb1d0e..0b47c890 100644 --- a/tree/migrations/migrations.go +++ b/tree/migrations/migrations.go @@ -36,8 +36,8 @@ func MigrationsWithPrefix(prefix string) []*migrate.Migration { return []*migrate.Migration{ { Id: prefix + "tree001", - Up: []string{strings.Replace(mig001splitted[1], dbPrefixReplacer, prefix, -1)}, - Down: []string{strings.Replace(mig001splitted[0], dbPrefixReplacer, prefix, -1)}, + Up: []string{strings.ReplaceAll(mig001splitted[1], dbPrefixReplacer, prefix)}, + Down: []string{strings.ReplaceAll(mig001splitted[0], dbPrefixReplacer, prefix)}, }, } } diff --git a/tree/tree.go b/tree/tree.go index 6d10834b..3a75e844 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -9,7 +9,6 @@ import ( "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/tree/types" "github.com/ethereum/go-ethereum/common" - "github.com/mattn/go-sqlite3" "github.com/russross/meddler" "golang.org/x/crypto/sha3" ) @@ -157,8 +156,7 @@ func (t *Tree) storeNodes(tx *db.Tx, nodes []types.TreeNode) error { for i := 0; i < len(nodes); i++ { if err := meddler.Insert(tx, t.rhtTable, &nodes[i]); err != nil { if sqliteErr, ok := db.SQLiteErr(err); ok { - uniqueConstraint := sqlite3.ErrNoExtended(1555) // 1555 is the error code for primary key violation - if sqliteErr.ExtendedCode == uniqueConstraint { + if sqliteErr.ExtendedCode == db.UniqueConstrain { // ignore repeated entries. This is likely to happen due to not // cleaning RHT when reorg continue From 9b39da59918e72d81a503b2c05a7ad23feb19e1d Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 12 Sep 2024 16:32:46 +0200 Subject: [PATCH 26/31] fix linter III --- test/helpers/aggoracle_e2e.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/helpers/aggoracle_e2e.go b/test/helpers/aggoracle_e2e.go index b43ce5e9..3c72d3cc 100644 --- a/test/helpers/aggoracle_e2e.go +++ b/test/helpers/aggoracle_e2e.go @@ -113,9 +113,7 @@ func CommonSetup(t *testing.T) ( require.NoError(t, err) // Syncer dbPathSyncer := path.Join(t.TempDir(), "file::memory:?cache=shared") - maxRetries := 3 - syncBlockChunkSize := uint64(10) - syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerL1Addr, common.Address{}, syncBlockChunkSize, etherman.LatestBlock, reorg, l1Client.Client(), time.Millisecond, 0, 100*time.Millisecond, maxRetries) + syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerL1Addr, common.Address{}, 10, etherman.LatestBlock, reorg, l1Client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3) require.NoError(t, err) go syncer.Start(ctx) From 4a9d124f6b80111508971b82ae65d0ae3cff2d14 Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 12 Sep 2024 16:46:48 +0200 Subject: [PATCH 27/31] fix linter --- bridgesync/migrations/migrations.go | 3 +-- l1infotreesync/l1infotreesync.go | 6 +++++- l1infotreesync/migrations/migrations.go | 3 +-- l1infotreesync/processor.go | 11 ++++++++--- test/helpers/aggoracle_e2e.go | 13 ++++++++----- tree/migrations/migrations.go | 3 +-- 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/bridgesync/migrations/migrations.go b/bridgesync/migrations/migrations.go index 588948b8..a6ee27b3 100644 --- a/bridgesync/migrations/migrations.go +++ b/bridgesync/migrations/migrations.go @@ -1,13 +1,12 @@ package migrations import ( + _ "embed" "strings" "github.com/0xPolygon/cdk/db" treeMigrations "github.com/0xPolygon/cdk/tree/migrations" migrate "github.com/rubenv/sql-migrate" - - _ "embed" ) const upDownSeparator = "-- +migrate Up" diff --git a/l1infotreesync/l1infotreesync.go b/l1infotreesync/l1infotreesync.go index adb28413..546a8ead 100644 --- a/l1infotreesync/l1infotreesync.go +++ b/l1infotreesync/l1infotreesync.go @@ -99,7 +99,11 @@ func (s *L1InfoTreeSync) GetL1InfoTreeMerkleProof(ctx context.Context, index uin } // GetRollupExitTreeMerkleProof creates a merkle proof for the rollup exit tree -func (s *L1InfoTreeSync) GetRollupExitTreeMerkleProof(ctx context.Context, networkID uint32, root common.Hash) (types.Proof, error) { +func (s *L1InfoTreeSync) GetRollupExitTreeMerkleProof( + ctx context.Context, + networkID uint32, + root common.Hash, +) (types.Proof, error) { if networkID == 0 { return tree.EmptyProof, nil } diff --git a/l1infotreesync/migrations/migrations.go b/l1infotreesync/migrations/migrations.go index 6823a2cf..e8861573 100644 --- a/l1infotreesync/migrations/migrations.go +++ b/l1infotreesync/migrations/migrations.go @@ -1,14 +1,13 @@ package migrations import ( + _ "embed" "strings" "github.com/0xPolygon/cdk/db" "github.com/0xPolygon/cdk/log" treeMigrations "github.com/0xPolygon/cdk/tree/migrations" migrate "github.com/rubenv/sql-migrate" - - _ "embed" ) const ( diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index 47e5dd5e..b6292245 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -111,7 +111,9 @@ func newProcessor(dbPath string) (*processor, error) { } // GetL1InfoTreeMerkleProof creates a merkle proof for the L1 Info tree -func (p *processor) GetL1InfoTreeMerkleProof(ctx context.Context, index uint32) (treeTypes.Proof, treeTypes.Root, error) { +func (p *processor) GetL1InfoTreeMerkleProof( + ctx context.Context, index uint32, +) (treeTypes.Proof, treeTypes.Root, error) { root, err := p.l1InfoTree.GetRootByIndex(ctx, index) if err != nil { return treeTypes.Proof{}, treeTypes.Root{}, err @@ -243,7 +245,7 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { var initialL1InfoIndex uint32 var l1InfoLeavesAdded uint32 lastIndex, err := p.getLastIndex(tx) - if err == ErrNotFound { + if errors.Is(err, ErrNotFound) { initialL1InfoIndex = 0 err = nil } else if err != nil { @@ -252,7 +254,10 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { initialL1InfoIndex = lastIndex + 1 } for _, e := range b.Events { - event := e.(Event) + event, ok := e.(Event) + if !ok { + return errors.New("failed to convert from sync.Block.Event into Event") + } if event.UpdateL1InfoTree != nil { index := initialL1InfoIndex + l1InfoLeavesAdded info := &L1InfoTreeLeaf{ diff --git a/test/helpers/aggoracle_e2e.go b/test/helpers/aggoracle_e2e.go index 3c72d3cc..77f5d99a 100644 --- a/test/helpers/aggoracle_e2e.go +++ b/test/helpers/aggoracle_e2e.go @@ -27,10 +27,13 @@ import ( ) const ( - NetworkIDL2 = uint32(1) - chainID = 1337 - initialBalance = "10000000000000000000000000" - blockGasLimit = uint64(999999999999999999) + NetworkIDL2 = uint32(1) + chainID = 1337 + initialBalance = "10000000000000000000000000" + blockGasLimit = uint64(999999999999999999) + syncBlockChunkSize = 10 + retries = 3 + periodRetry = time.Millisecond * 100 ) type AggoracleWithEVMChainEnv struct { @@ -113,7 +116,7 @@ func CommonSetup(t *testing.T) ( require.NoError(t, err) // Syncer dbPathSyncer := path.Join(t.TempDir(), "file::memory:?cache=shared") - syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerL1Addr, common.Address{}, 10, etherman.LatestBlock, reorg, l1Client.Client(), time.Millisecond, 0, 100*time.Millisecond, 3) + syncer, err := l1infotreesync.New(ctx, dbPathSyncer, gerL1Addr, common.Address{}, syncBlockChunkSize, etherman.LatestBlock, reorg, l1Client.Client(), time.Millisecond, 0, periodRetry, retries) require.NoError(t, err) go syncer.Start(ctx) diff --git a/tree/migrations/migrations.go b/tree/migrations/migrations.go index 0b47c890..63fa6a8c 100644 --- a/tree/migrations/migrations.go +++ b/tree/migrations/migrations.go @@ -1,12 +1,11 @@ package migrations import ( + _ "embed" "strings" "github.com/0xPolygon/cdk/db" migrate "github.com/rubenv/sql-migrate" - - _ "embed" ) const ( From 3f28c15d4f6f923446396023564bab77eb8af307 Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 12 Sep 2024 16:54:37 +0200 Subject: [PATCH 28/31] increase linter TO --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fa71f98a..fa91bd7e 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,7 @@ install-linter: ## Installs the linter .PHONY: lint lint: ## Runs the linter - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/golangci-lint run + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/golangci-lint run --timeout 1m $(VENV_PYTHON): rm -rf $(VENV) From 1f2b35b8fad75be470e6e85747acc5c462b79aca Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 12 Sep 2024 17:56:21 +0200 Subject: [PATCH 29/31] fix UTs and lint --- bridgesync/claimcalldata_test.go | 2 ++ bridgesync/processor.go | 61 +++++++++++++++++++------------- bridgesync/processor_test.go | 8 +++-- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/bridgesync/claimcalldata_test.go b/bridgesync/claimcalldata_test.go index d788c2c7..1319835b 100644 --- a/bridgesync/claimcalldata_test.go +++ b/bridgesync/claimcalldata_test.go @@ -28,6 +28,7 @@ type testCase struct { func TestClaimCalldata(t *testing.T) { testCases := []testCase{} // Setup Docker L1 + log.Debug("starting docker") ctx := context.Background() msg, err := exec.Command("bash", "-l", "-c", "docker compose up -d").CombinedOutput() require.NoError(t, err, string(msg)) @@ -36,6 +37,7 @@ func TestClaimCalldata(t *testing.T) { msg, err = exec.Command("bash", "-l", "-c", "docker compose down").CombinedOutput() require.NoError(t, err, string(msg)) }() + log.Debug("docker started") client, err := ethclient.Dial("http://localhost:8545") require.NoError(t, err) privateKey, err := crypto.HexToECDSA("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") diff --git a/bridgesync/processor.go b/bridgesync/processor.go index 942ec9b1..b34416a0 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -5,6 +5,7 @@ import ( "database/sql" "encoding/binary" "errors" + "fmt" "math/big" "github.com/0xPolygon/cdk/bridgesync/migrations" @@ -120,11 +121,24 @@ func newProcessor(dbPath, loggerPrefix string) (*processor, error) { func (p *processor) GetBridges( ctx context.Context, fromBlock, toBlock uint64, ) ([]Bridge, error) { - bridgePtrs := []*Bridge{} - bridgesIface, err := p.getTypeFromBlockToBlock(ctx, fromBlock, toBlock, "bridge", bridgePtrs) + tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) + if err != nil { + return nil, err + } + defer func() { + if err := tx.Rollback(); err != nil { + log.Warnf("error rolling back tx: %v", err) + } + }() + rows, err := p.queryBlockRange(tx, fromBlock, toBlock, "bridge") if err != nil { return nil, err } + bridgePtrs := []*Bridge{} + if err = meddler.ScanAll(rows, &bridgePtrs); err != nil { + return nil, err + } + bridgesIface := db.SlicePtrsToSlice(bridgePtrs) bridges, ok := bridgesIface.([]Bridge) if !ok { return nil, errors.New("failed to convert from []*Bridge to []Bridge") @@ -135,21 +149,6 @@ func (p *processor) GetBridges( func (p *processor) GetClaims( ctx context.Context, fromBlock, toBlock uint64, ) ([]Claim, error) { - claimPtrs := []*Claim{} - claimsIface, err := p.getTypeFromBlockToBlock(ctx, fromBlock, toBlock, "claim", claimPtrs) - if err != nil { - return nil, err - } - claims, ok := claimsIface.([]Claim) - if !ok { - return nil, errors.New("failed to convert from []*Claim to []Claim") - } - return claims, nil -} - -func (p *processor) getTypeFromBlockToBlock( - ctx context.Context, fromBlock, toBlock uint64, table string, typeToQuery interface{}, -) (interface{}, error) { tx, err := p.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) if err != nil { return nil, err @@ -159,23 +158,37 @@ func (p *processor) getTypeFromBlockToBlock( log.Warnf("error rolling back tx: %v", err) } }() - - if err = p.isBlockProcessed(tx, toBlock); err != nil { + rows, err := p.queryBlockRange(tx, fromBlock, toBlock, "claim") + if err != nil { + return nil, err + } + claimPtrs := []*Claim{} + if err = meddler.ScanAll(rows, &claimPtrs); err != nil { return nil, err } + claimsIface := db.SlicePtrsToSlice(claimPtrs) + claims, ok := claimsIface.([]Claim) + if !ok { + return nil, errors.New("failed to convert from []*Claim to []Claim") + } + return claims, nil +} - err = meddler.QueryAll(tx, typeToQuery, ` - SELECT * FROM `+table+` +func (p *processor) queryBlockRange(tx db.DBer, fromBlock, toBlock uint64, table string) (*sql.Rows, error) { + if err := p.isBlockProcessed(tx, toBlock); err != nil { + return nil, err + } + rows, err := tx.Query(fmt.Sprintf(` + SELECT * FROM %s WHERE block_num >= $1 AND block_num <= $2; - `, fromBlock, toBlock) + `, table), fromBlock, toBlock) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } return nil, err } - - return db.SlicePtrsToSlice(typeToQuery), nil + return rows, nil } func (p *processor) isBlockProcessed(tx db.DBer, blockNum uint64) error { diff --git a/bridgesync/processor_test.go b/bridgesync/processor_test.go index 5578cee5..2ff03c76 100644 --- a/bridgesync/processor_test.go +++ b/bridgesync/processor_test.go @@ -420,10 +420,11 @@ func (a *getClaims) desc() string { return a.description } -func (a *getClaims) execute(t *testing.T) { //nolint:thelper +func (a *getClaims) execute(t *testing.T) { + t.Helper() actualEvents, actualErr := a.p.GetClaims(a.ctx, a.fromBlock, a.toBlock) - require.Equal(t, a.expectedClaims, actualEvents) require.Equal(t, a.expectedErr, actualErr) + require.Equal(t, a.expectedClaims, actualEvents) } // GetBridges @@ -446,7 +447,8 @@ func (a *getBridges) desc() string { return a.description } -func (a *getBridges) execute(t *testing.T) { //nolint:thelper +func (a *getBridges) execute(t *testing.T) { + t.Helper() actualEvents, actualErr := a.p.GetBridges(a.ctx, a.fromBlock, a.toBlock) require.Equal(t, a.expectedBridges, actualEvents) require.Equal(t, a.expectedErr, actualErr) From 12904e50cbe8ac02fbb37e426052ab7a577a9d2e Mon Sep 17 00:00:00 2001 From: Arnau Date: Thu, 12 Sep 2024 18:29:16 +0200 Subject: [PATCH 30/31] increase linter TO --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fa91bd7e..7f8ff33b 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,7 @@ install-linter: ## Installs the linter .PHONY: lint lint: ## Runs the linter - export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/golangci-lint run --timeout 1m + export "GOROOT=$$(go env GOROOT)" && $$(go env GOPATH)/bin/golangci-lint run --timeout 5m $(VENV_PYTHON): rm -rf $(VENV) From 34ad89dc3666edb3f349bf11aa3014aa9ccbd0fa Mon Sep 17 00:00:00 2001 From: Arnau Date: Fri, 13 Sep 2024 15:30:44 +0200 Subject: [PATCH 31/31] add PR requests --- bridgesync/migrations/migrations.go | 26 ++++--------- bridgesync/processor.go | 6 +-- .../datacommittee/datacommittee_test.go | 3 +- db/interface.go | 12 +++++- db/migrations.go | 25 +++++++++++- db/tx.go | 23 ++++++++--- db/types/types.go | 7 ++++ l1infotreesync/e2e_test.go | 30 --------------- l1infotreesync/migrations/migrations.go | 38 +++++++++---------- l1infotreesync/processor.go | 4 +- tree/appendonlytree.go | 4 +- tree/migrations/migrations.go | 30 +++------------ tree/tree.go | 12 +++--- tree/updatabletree.go | 2 +- 14 files changed, 103 insertions(+), 119 deletions(-) create mode 100644 db/types/types.go diff --git a/bridgesync/migrations/migrations.go b/bridgesync/migrations/migrations.go index a6ee27b3..c500ee38 100644 --- a/bridgesync/migrations/migrations.go +++ b/bridgesync/migrations/migrations.go @@ -2,32 +2,22 @@ package migrations import ( _ "embed" - "strings" "github.com/0xPolygon/cdk/db" + "github.com/0xPolygon/cdk/db/types" treeMigrations "github.com/0xPolygon/cdk/tree/migrations" - migrate "github.com/rubenv/sql-migrate" ) -const upDownSeparator = "-- +migrate Up" - //go:embed bridgesync0001.sql var mig001 string -var mig001splitted = strings.Split(mig001, upDownSeparator) -var bridgeMigrations = &migrate.MemoryMigrationSource{ - Migrations: []*migrate.Migration{ +func RunMigrations(dbPath string) error { + migrations := []types.Migration{ { - Id: "bridgesync001", - Up: []string{mig001splitted[1]}, - Down: []string{mig001splitted[0]}, + ID: "bridgesync0001", + SQL: mig001, }, - }, -} - -func RunMigrations(dbPath string) error { - return db.RunMigrations(dbPath, &migrate.MemoryMigrationSource{Migrations: append( - bridgeMigrations.Migrations, - treeMigrations.Migrations.Migrations..., - )}) + } + migrations = append(migrations, treeMigrations.Migrations...) + return db.RunMigrations(dbPath, migrations) } diff --git a/bridgesync/processor.go b/bridgesync/processor.go index b34416a0..47b26595 100644 --- a/bridgesync/processor.go +++ b/bridgesync/processor.go @@ -174,7 +174,7 @@ func (p *processor) GetClaims( return claims, nil } -func (p *processor) queryBlockRange(tx db.DBer, fromBlock, toBlock uint64, table string) (*sql.Rows, error) { +func (p *processor) queryBlockRange(tx db.Querier, fromBlock, toBlock uint64, table string) (*sql.Rows, error) { if err := p.isBlockProcessed(tx, toBlock); err != nil { return nil, err } @@ -191,7 +191,7 @@ func (p *processor) queryBlockRange(tx db.DBer, fromBlock, toBlock uint64, table return rows, nil } -func (p *processor) isBlockProcessed(tx db.DBer, blockNum uint64) error { +func (p *processor) isBlockProcessed(tx db.Querier, blockNum uint64) error { lpb, err := p.getLastProcessedBlockWithTx(tx) if err != nil { return err @@ -208,7 +208,7 @@ func (p *processor) GetLastProcessedBlock(ctx context.Context) (uint64, error) { return p.getLastProcessedBlockWithTx(p.db) } -func (p *processor) getLastProcessedBlockWithTx(tx db.DBer) (uint64, error) { +func (p *processor) getLastProcessedBlockWithTx(tx db.Querier) (uint64, error) { var lastProcessedBlock uint64 row := tx.QueryRow("SELECT num FROM BLOCK ORDER BY num DESC LIMIT 1;") err := row.Scan(&lastProcessedBlock) diff --git a/dataavailability/datacommittee/datacommittee_test.go b/dataavailability/datacommittee/datacommittee_test.go index ad128324..fcacef3c 100644 --- a/dataavailability/datacommittee/datacommittee_test.go +++ b/dataavailability/datacommittee/datacommittee_test.go @@ -2,7 +2,6 @@ package datacommittee import ( "errors" - "fmt" "math/big" "testing" @@ -164,7 +163,7 @@ func deployDACProxy(auth *bind.TransactOpts, client bind.ContractBackend, dacImp if err != nil { return common.Address{}, err } - fmt.Println("DAC proxy deployed at", proxyAddr) + log.Debugf("DAC proxy deployed at", proxyAddr) return proxyAddr, nil } diff --git a/db/interface.go b/db/interface.go index acf73ca3..03f81aba 100644 --- a/db/interface.go +++ b/db/interface.go @@ -1,9 +1,17 @@ package db -import "database/sql" +import ( + "context" + "database/sql" +) -type DBer interface { +type Querier interface { Exec(query string, args ...interface{}) (sql.Result, error) Query(query string, args ...interface{}) (*sql.Rows, error) QueryRow(query string, args ...interface{}) *sql.Row } + +type DBer interface { + Querier + BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error) +} diff --git a/db/migrations.go b/db/migrations.go index 07315375..1a56874e 100644 --- a/db/migrations.go +++ b/db/migrations.go @@ -2,22 +2,43 @@ package db import ( "fmt" + "strings" + "github.com/0xPolygon/cdk/db/types" "github.com/0xPolygon/cdk/log" _ "github.com/mattn/go-sqlite3" migrate "github.com/rubenv/sql-migrate" ) +const ( + upDownSeparator = "-- +migrate Up" + dbPrefixReplacer = "/*dbprefix*/" +) + // RunMigrations will execute pending migrations if needed to keep // the database updated with the latest changes in either direction, // up or down. -func RunMigrations(dbPath string, migrations migrate.MigrationSource) error { +func RunMigrations(dbPath string, migrations []types.Migration) error { db, err := NewSQLiteDB(dbPath) if err != nil { return fmt.Errorf("error creating DB %w", err) } + migs := &migrate.MemoryMigrationSource{Migrations: []*migrate.Migration{}} + for _, m := range migrations { + prefixed := strings.ReplaceAll(m.SQL, dbPrefixReplacer, m.Prefix) + splitted := strings.Split(prefixed, upDownSeparator) + migs.Migrations = append(migs.Migrations, &migrate.Migration{ + Id: m.Prefix + m.ID, + Up: []string{splitted[1]}, + Down: []string{splitted[0]}, + }) + } - nMigrations, err := migrate.Exec(db, "sqlite3", migrations, migrate.Up) + log.Debugf("running migrations:") + for _, m := range migs.Migrations { + log.Debugf("%+v", m.Id) + } + nMigrations, err := migrate.Exec(db, "sqlite3", migs, migrate.Up) if err != nil { return fmt.Errorf("error executing migration %w", err) } diff --git a/db/tx.go b/db/tx.go index dc22750e..926da07c 100644 --- a/db/tx.go +++ b/db/tx.go @@ -2,22 +2,33 @@ package db import ( "context" - "database/sql" ) +type SQLTxer interface { + Querier + Commit() error + Rollback() error +} + +type Txer interface { + SQLTxer + AddRollbackCallback(cb func()) + AddCommitCallback(cb func()) +} + type Tx struct { - *sql.Tx + SQLTxer rollbackCallbacks []func() commitCallbacks []func() } -func NewTx(ctx context.Context, db *sql.DB) (*Tx, error) { +func NewTx(ctx context.Context, db DBer) (Txer, error) { tx, err := db.BeginTx(ctx, nil) if err != nil { return nil, err } return &Tx{ - Tx: tx, + SQLTxer: tx, }, nil } @@ -29,7 +40,7 @@ func (s *Tx) AddCommitCallback(cb func()) { } func (s *Tx) Commit() error { - if err := s.Tx.Commit(); err != nil { + if err := s.SQLTxer.Commit(); err != nil { return err } for _, cb := range s.commitCallbacks { @@ -39,7 +50,7 @@ func (s *Tx) Commit() error { } func (s *Tx) Rollback() error { - if err := s.Tx.Rollback(); err != nil { + if err := s.SQLTxer.Rollback(); err != nil { return err } for _, cb := range s.rollbackCallbacks { diff --git a/db/types/types.go b/db/types/types.go new file mode 100644 index 00000000..ade19092 --- /dev/null +++ b/db/types/types.go @@ -0,0 +1,7 @@ +package types + +type Migration struct { + ID string + SQL string + Prefix string +} diff --git a/l1infotreesync/e2e_test.go b/l1infotreesync/e2e_test.go index 989e347e..90f7f091 100644 --- a/l1infotreesync/e2e_test.go +++ b/l1infotreesync/e2e_test.go @@ -135,36 +135,6 @@ func TestE2E(t *testing.T) { } } -func TestFinalised(t *testing.T) { - ctx := context.Background() - privateKey, err := crypto.GenerateKey() - require.NoError(t, err) - auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(1337)) - require.NoError(t, err) - client, _, _, _, _, err := newSimulatedClient(auth) //nolint:dogsled - require.NoError(t, err) - for i := 0; i < 100; i++ { - client.Commit() - } - - n4, err := client.Client().HeaderByNumber(ctx, big.NewInt(-4)) - require.NoError(t, err) - fmt.Println("-4", n4.Number) - n3, err := client.Client().HeaderByNumber(ctx, big.NewInt(-3)) - require.NoError(t, err) - fmt.Println("-3", n3.Number) - n2, err := client.Client().HeaderByNumber(ctx, big.NewInt(-2)) - require.NoError(t, err) - fmt.Println("-2", n2.Number) - n1, err := client.Client().HeaderByNumber(ctx, big.NewInt(-1)) - require.NoError(t, err) - fmt.Println("-1", n1.Number) - n0, err := client.Client().HeaderByNumber(ctx, nil) - require.NoError(t, err) - fmt.Println("0", n0.Number) - fmt.Printf("amount of blocks latest - finalised: %d", n0.Number.Uint64()-n3.Number.Uint64()) -} - func TestStressAndReorgs(t *testing.T) { const ( totalIterations = 200 // Have tested with much larger number (+10k) diff --git a/l1infotreesync/migrations/migrations.go b/l1infotreesync/migrations/migrations.go index e8861573..768dde37 100644 --- a/l1infotreesync/migrations/migrations.go +++ b/l1infotreesync/migrations/migrations.go @@ -2,40 +2,38 @@ package migrations import ( _ "embed" - "strings" "github.com/0xPolygon/cdk/db" - "github.com/0xPolygon/cdk/log" + "github.com/0xPolygon/cdk/db/types" treeMigrations "github.com/0xPolygon/cdk/tree/migrations" - migrate "github.com/rubenv/sql-migrate" ) const ( - upDownSeparator = "-- +migrate Up" RollupExitTreePrefix = "rollup_exit_" L1InfoTreePrefix = "l1_info_" ) //go:embed l1infotreesync0001.sql var mig001 string -var mig001splitted = strings.Split(mig001, upDownSeparator) -var Migrations = &migrate.MemoryMigrationSource{ - Migrations: []*migrate.Migration{ +func RunMigrations(dbPath string) error { + migrations := []types.Migration{ { - Id: "l1infotreesync0001", - Up: []string{mig001splitted[1]}, - Down: []string{mig001splitted[0]}, + ID: "l1infotreesync0001", + SQL: mig001, }, - }, -} - -func RunMigrations(dbPath string) error { - migs := treeMigrations.MigrationsWithPrefix(RollupExitTreePrefix) - migs = append(migs, treeMigrations.MigrationsWithPrefix(L1InfoTreePrefix)...) - migs = append(migs, Migrations.Migrations...) - for _, m := range migs { - log.Debugf("%+v", m.Id) } - return db.RunMigrations(dbPath, &migrate.MemoryMigrationSource{Migrations: migs}) + for _, tm := range treeMigrations.Migrations { + migrations = append(migrations, types.Migration{ + ID: tm.ID, + SQL: tm.SQL, + Prefix: RollupExitTreePrefix, + }) + migrations = append(migrations, types.Migration{ + ID: tm.ID, + SQL: tm.SQL, + Prefix: L1InfoTreePrefix, + }) + } + return db.RunMigrations(dbPath, migrations) } diff --git a/l1infotreesync/processor.go b/l1infotreesync/processor.go index b6292245..781d4478 100644 --- a/l1infotreesync/processor.go +++ b/l1infotreesync/processor.go @@ -178,7 +178,7 @@ func (p *processor) GetLastProcessedBlock(ctx context.Context) (uint64, error) { return p.getLastProcessedBlockWithTx(p.db) } -func (p *processor) getLastProcessedBlockWithTx(tx db.DBer) (uint64, error) { +func (p *processor) getLastProcessedBlockWithTx(tx db.Querier) (uint64, error) { var lastProcessedBlock uint64 row := tx.QueryRow("SELECT num FROM BLOCK ORDER BY num DESC LIMIT 1;") err := row.Scan(&lastProcessedBlock) @@ -309,7 +309,7 @@ func (p *processor) ProcessBlock(ctx context.Context, b sync.Block) error { return nil } -func (p *processor) getLastIndex(tx db.DBer) (uint32, error) { +func (p *processor) getLastIndex(tx db.Querier) (uint32, error) { var lastProcessedIndex uint32 row := tx.QueryRow("SELECT position FROM l1info_leaf ORDER BY block_num DESC, block_pos DESC LIMIT 1;") err := row.Scan(&lastProcessedIndex) diff --git a/tree/appendonlytree.go b/tree/appendonlytree.go index d527a819..20d22ec1 100644 --- a/tree/appendonlytree.go +++ b/tree/appendonlytree.go @@ -28,7 +28,7 @@ func NewAppendOnlyTree(db *sql.DB, dbPrefix string) *AppendOnlyTree { } } -func (t *AppendOnlyTree) AddLeaf(tx *db.Tx, blockNum, blockPosition uint64, leaf types.Leaf) error { +func (t *AppendOnlyTree) AddLeaf(tx db.Txer, blockNum, blockPosition uint64, leaf types.Leaf) error { if int64(leaf.Index) != t.lastIndex+1 { // rebuild cache if err := t.initCache(tx); err != nil { @@ -78,7 +78,7 @@ func (t *AppendOnlyTree) AddLeaf(tx *db.Tx, blockNum, blockPosition uint64, leaf return nil } -func (t *AppendOnlyTree) initCache(tx *db.Tx) error { +func (t *AppendOnlyTree) initCache(tx db.Txer) error { siblings := [types.DefaultHeight]common.Hash{} lastRoot, err := t.getLastRootWithTx(tx) if err != nil { diff --git a/tree/migrations/migrations.go b/tree/migrations/migrations.go index 63fa6a8c..dd5847e7 100644 --- a/tree/migrations/migrations.go +++ b/tree/migrations/migrations.go @@ -2,41 +2,21 @@ package migrations import ( _ "embed" - "strings" "github.com/0xPolygon/cdk/db" - migrate "github.com/rubenv/sql-migrate" -) - -const ( - upDownSeparator = "-- +migrate Up" - dbPrefixReplacer = "/*dbprefix*/" + "github.com/0xPolygon/cdk/db/types" ) //go:embed tree0001.sql var mig001 string -var mig001splitted = strings.Split(mig001, upDownSeparator) -var Migrations = &migrate.MemoryMigrationSource{ - Migrations: []*migrate.Migration{ - { - Id: "tree001", - Up: []string{mig001splitted[1]}, - Down: []string{mig001splitted[0]}, - }, +var Migrations = []types.Migration{ + { + ID: "tree001", + SQL: mig001, }, } func RunMigrations(dbPath string) error { return db.RunMigrations(dbPath, Migrations) } - -func MigrationsWithPrefix(prefix string) []*migrate.Migration { - return []*migrate.Migration{ - { - Id: prefix + "tree001", - Up: []string{strings.ReplaceAll(mig001splitted[1], dbPrefixReplacer, prefix)}, - Down: []string{strings.ReplaceAll(mig001splitted[0], dbPrefixReplacer, prefix)}, - }, - } -} diff --git a/tree/tree.go b/tree/tree.go index 3a75e844..2107ba68 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -49,7 +49,7 @@ func newTree(db *sql.DB, tablePrefix string) *Tree { return t } -func (t *Tree) getSiblings(tx db.DBer, index uint32, root common.Hash) ( +func (t *Tree) getSiblings(tx db.Querier, index uint32, root common.Hash) ( siblings [32]common.Hash, hasUsedZeroHashes bool, err error, @@ -118,7 +118,7 @@ func (t *Tree) GetProof(ctx context.Context, index uint32, root common.Hash) (ty return siblings, nil } -func (t *Tree) getRHTNode(tx db.DBer, nodeHash common.Hash) (*types.TreeNode, error) { +func (t *Tree) getRHTNode(tx db.Querier, nodeHash common.Hash) (*types.TreeNode, error) { node := &types.TreeNode{} err := meddler.QueryRow( tx, node, @@ -152,7 +152,7 @@ func generateZeroHashes(height uint8) []common.Hash { return zeroHashes } -func (t *Tree) storeNodes(tx *db.Tx, nodes []types.TreeNode) error { +func (t *Tree) storeNodes(tx db.Txer, nodes []types.TreeNode) error { for i := 0; i < len(nodes); i++ { if err := meddler.Insert(tx, t.rhtTable, &nodes[i]); err != nil { if sqliteErr, ok := db.SQLiteErr(err); ok { @@ -168,7 +168,7 @@ func (t *Tree) storeNodes(tx *db.Tx, nodes []types.TreeNode) error { return nil } -func (t *Tree) storeRoot(tx *db.Tx, root types.Root) error { +func (t *Tree) storeRoot(tx db.Txer, root types.Root) error { return meddler.Insert(tx, t.rootTable, &root) } @@ -177,7 +177,7 @@ func (t *Tree) GetLastRoot(ctx context.Context) (types.Root, error) { return t.getLastRootWithTx(t.db) } -func (t *Tree) getLastRootWithTx(tx db.DBer) (types.Root, error) { +func (t *Tree) getLastRootWithTx(tx db.Querier) (types.Root, error) { var root types.Root err := meddler.QueryRow( tx, &root, @@ -242,7 +242,7 @@ func (t *Tree) GetLeaf(ctx context.Context, index uint32, root common.Hash) (com } // Reorg deletes all the data relevant from firstReorgedBlock (includded) and onwards -func (t *Tree) Reorg(tx *db.Tx, firstReorgedBlock uint64) error { +func (t *Tree) Reorg(tx db.Txer, firstReorgedBlock uint64) error { _, err := tx.Exec( fmt.Sprintf(`DELETE FROM %s WHERE block_num >= $1`, t.rootTable), firstReorgedBlock, diff --git a/tree/updatabletree.go b/tree/updatabletree.go index 4e9f753f..3ed8b881 100644 --- a/tree/updatabletree.go +++ b/tree/updatabletree.go @@ -23,7 +23,7 @@ func NewUpdatableTree(db *sql.DB, dbPrefix string) *UpdatableTree { return ut } -func (t *UpdatableTree) UpsertLeaf(tx *db.Tx, blockNum, blockPosition uint64, leaf types.Leaf) error { +func (t *UpdatableTree) UpsertLeaf(tx db.Txer, blockNum, blockPosition uint64, leaf types.Leaf) error { var rootHash common.Hash root, err := t.getLastRootWithTx(tx) if err != nil {