From fc3df5e9aaa16f11761f939f3dbff81036da2fd2 Mon Sep 17 00:00:00 2001 From: Arnau Date: Mon, 29 Jul 2024 18:44:00 +0200 Subject: [PATCH] Implement base addLeaf --- .../bridgesync.go | 66 +++++++++++++-- {localbridgesync => bridgesync}/downloader.go | 2 +- {localbridgesync => bridgesync}/e2e_test.go | 2 +- {localbridgesync => bridgesync}/processor.go | 44 +++++----- .../processor_test.go | 4 +- bridgesync/tree.go | 82 +++++++++++++++++++ 6 files changed, 169 insertions(+), 31 deletions(-) rename localbridgesync/localbridgesync.go => bridgesync/bridgesync.go (54%) rename {localbridgesync => bridgesync}/downloader.go (99%) rename {localbridgesync => bridgesync}/e2e_test.go (68%) rename {localbridgesync => bridgesync}/processor.go (80%) rename {localbridgesync => bridgesync}/processor_test.go (99%) create mode 100644 bridgesync/tree.go diff --git a/localbridgesync/localbridgesync.go b/bridgesync/bridgesync.go similarity index 54% rename from localbridgesync/localbridgesync.go rename to bridgesync/bridgesync.go index d0617584..2a95acb9 100644 --- a/localbridgesync/localbridgesync.go +++ b/bridgesync/bridgesync.go @@ -1,4 +1,4 @@ -package localbridgesync +package bridgesync import ( "context" @@ -10,7 +10,10 @@ import ( ) const ( - reorgDetectorID = "localbridgesync" + reorgDetectorIDL1 = "bridgesyncl1" + reorgDetectorIDL2 = "bridgesyncl2" + dbPrefixL1 = "bridgesyncl1" + dbPrefixL2 = "bridgesyncl2" downloadBufferSize = 1000 ) @@ -24,17 +27,66 @@ type LocalBridgeSync struct { driver *sync.EVMDriver } -func New( +func NewL1( ctx context.Context, dbPath string, bridge common.Address, syncBlockChunkSize uint64, blockFinalityType etherman.BlockNumberFinality, rd sync.ReorgDetector, - l2Client EthClienter, + ethClient EthClienter, initialBlock uint64, ) (*LocalBridgeSync, error) { - processor, err := newProcessor(dbPath) + return new( + ctx, + dbPath, + bridge, + syncBlockChunkSize, + blockFinalityType, + rd, + ethClient, + initialBlock, + dbPrefixL1, + reorgDetectorIDL1, + ) +} + +func NewL2( + ctx context.Context, + dbPath string, + bridge common.Address, + syncBlockChunkSize uint64, + blockFinalityType etherman.BlockNumberFinality, + rd sync.ReorgDetector, + ethClient EthClienter, + initialBlock uint64, +) (*LocalBridgeSync, error) { + return new( + ctx, + dbPath, + bridge, + syncBlockChunkSize, + blockFinalityType, + rd, + ethClient, + initialBlock, + dbPrefixL1, + reorgDetectorIDL1, + ) +} + +func new( + ctx context.Context, + dbPath string, + bridge common.Address, + syncBlockChunkSize uint64, + blockFinalityType etherman.BlockNumberFinality, + rd sync.ReorgDetector, + ethClient EthClienter, + initialBlock uint64, + dbPrefix, reorgDetectorID string, +) (*LocalBridgeSync, error) { + processor, err := newProcessor(dbPath, dbPrefix) if err != nil { return nil, err } @@ -51,12 +103,12 @@ func New( } } - appender, err := buildAppender(l2Client, bridge) + appender, err := buildAppender(ethClient, bridge) if err != nil { return nil, err } downloader, err := sync.NewEVMDownloader( - l2Client, + ethClient, syncBlockChunkSize, blockFinalityType, waitForNewBlocksPeriod, diff --git a/localbridgesync/downloader.go b/bridgesync/downloader.go similarity index 99% rename from localbridgesync/downloader.go rename to bridgesync/downloader.go index 5b6ab8f6..d2ef4e7c 100644 --- a/localbridgesync/downloader.go +++ b/bridgesync/downloader.go @@ -1,4 +1,4 @@ -package localbridgesync +package bridgesync import ( "fmt" diff --git a/localbridgesync/e2e_test.go b/bridgesync/e2e_test.go similarity index 68% rename from localbridgesync/e2e_test.go rename to bridgesync/e2e_test.go index c84d8d33..b7834fdf 100644 --- a/localbridgesync/e2e_test.go +++ b/bridgesync/e2e_test.go @@ -1,3 +1,3 @@ -package localbridgesync +package bridgesync // TODO: add E2E test, prolly need a mock contract diff --git a/localbridgesync/processor.go b/bridgesync/processor.go similarity index 80% rename from localbridgesync/processor.go rename to bridgesync/processor.go index 4a45c663..30738d01 100644 --- a/localbridgesync/processor.go +++ b/bridgesync/processor.go @@ -1,4 +1,4 @@ -package localbridgesync +package bridgesync import ( "context" @@ -14,8 +14,8 @@ import ( ) const ( - eventsTable = "localbridgesync-events" - lastBlockTable = "localbridgesync-lastBlock" + eventsTableSufix = "-events" + lastBlockTableSufix = "-lastBlock" ) var ( @@ -48,26 +48,30 @@ type Event struct { } type processor struct { - db kv.RwDB + db kv.RwDB + eventsTable string + lastBlockTable string } -func tableCfgFunc(defaultBuckets kv.TableCfg) kv.TableCfg { - return kv.TableCfg{ - eventsTable: {}, - lastBlockTable: {}, - } -} - -func newProcessor(dbPath string) (*processor, error) { +func newProcessor(dbPath, dbPrefix string) (*processor, error) { + eventsTable := dbPrefix + eventsTableSufix + lastBlockTable := dbPrefix + lastBlockTableSufix db, err := mdbx.NewMDBX(nil). Path(dbPath). - WithTableCfg(tableCfgFunc). + WithTableCfg(func(defaultBuckets kv.TableCfg) kv.TableCfg { + return kv.TableCfg{ + eventsTable: {}, + lastBlockTable: {}, + } + }). Open() if err != nil { return nil, err } return &processor{ - db: db, + db: db, + eventsTable: eventsTable, + lastBlockTable: lastBlockTable, }, nil } @@ -90,7 +94,7 @@ func (p *processor) GetClaimsAndBridges( if lpb < toBlock { return nil, ErrBlockNotProcessed } - c, err := tx.Cursor(eventsTable) + c, err := tx.Cursor(p.eventsTable) if err != nil { return nil, err } @@ -124,7 +128,7 @@ func (p *processor) GetLastProcessedBlock(ctx context.Context) (uint64, error) { } func (p *processor) getLastProcessedBlockWithTx(tx kv.Tx) (uint64, error) { - if blockNumBytes, err := tx.GetOne(lastBlockTable, lastBlokcKey); err != nil { + if blockNumBytes, err := tx.GetOne(p.lastBlockTable, lastBlokcKey); err != nil { return 0, err } else if blockNumBytes == nil { return 0, nil @@ -138,7 +142,7 @@ func (p *processor) Reorg(firstReorgedBlock uint64) error { if err != nil { return err } - c, err := tx.Cursor(eventsTable) + c, err := tx.Cursor(p.eventsTable) if err != nil { return err } @@ -149,7 +153,7 @@ func (p *processor) Reorg(firstReorgedBlock uint64) error { tx.Rollback() return err } - if err := tx.Delete(eventsTable, k); err != nil { + if err := tx.Delete(p.eventsTable, k); err != nil { tx.Rollback() return err } @@ -176,7 +180,7 @@ func (p *processor) ProcessBlock(block sync.Block) error { tx.Rollback() return err } - if err := tx.Put(eventsTable, common.Uint64To2Bytes(block.Num), value); err != nil { + if err := tx.Put(p.eventsTable, common.Uint64To2Bytes(block.Num), value); err != nil { tx.Rollback() return err } @@ -190,5 +194,5 @@ func (p *processor) ProcessBlock(block sync.Block) error { func (p *processor) updateLastProcessedBlock(tx kv.RwTx, blockNum uint64) error { blockNumBytes := common.Uint64To2Bytes(blockNum) - return tx.Put(lastBlockTable, lastBlokcKey, blockNumBytes) + return tx.Put(p.lastBlockTable, lastBlokcKey, blockNumBytes) } diff --git a/localbridgesync/processor_test.go b/bridgesync/processor_test.go similarity index 99% rename from localbridgesync/processor_test.go rename to bridgesync/processor_test.go index dbf0d74c..60bc6b19 100644 --- a/localbridgesync/processor_test.go +++ b/bridgesync/processor_test.go @@ -1,4 +1,4 @@ -package localbridgesync +package bridgesync import ( "context" @@ -14,7 +14,7 @@ import ( func TestProceessor(t *testing.T) { path := t.TempDir() - p, err := newProcessor(path) + p, err := newProcessor(path, "foo") require.NoError(t, err) actions := []processAction{ // processed: ~ diff --git a/bridgesync/tree.go b/bridgesync/tree.go new file mode 100644 index 00000000..0dbf7d84 --- /dev/null +++ b/bridgesync/tree.go @@ -0,0 +1,82 @@ +package bridgesync + +import ( + "errors" + "fmt" + + "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/kv" + "golang.org/x/crypto/sha3" +) + +type tree struct { + db kv.RwDB + lastIndex int64 + height uint8 + rightPathCache []common.Hash +} + +type treeNode struct { + left common.Hash + right common.Hash +} + +func (n *treeNode) hash() common.Hash { + var hash common.Hash + hasher := sha3.NewLegacyKeccak256() + hasher.Write(n.left[:]) + hasher.Write(n.right[:]) + copy(hash[:], hasher.Sum(nil)) + return hash +} + +func newTree() (*tree, error) { + // TODO: init lastIndex & rightPathCache + return &tree{}, errors.New("not implemented") +} + +func (t *tree) addLeaf(index uint, hash common.Hash) error { + if int64(index) != t.lastIndex+1 { + return fmt.Errorf("mismatched index. Expected: %d, actual: %d", t.lastIndex+1, index) + } + + currentChildHash := hash + leftIsFilled := true + newNodes := []treeNode{} + for h := uint8(0); h < t.height; h++ { + var parent treeNode + if index&(1< 0 { + // Add child to the right + var child common.Hash + copy(child[:], currentChildHash[:]) + parent = treeNode{ + left: t.rightPathCache[h], + right: child, + } + } else { + // Add child to the left + if leftIsFilled { + // if at this level the left is filled, it means that the new node will be in the right path + copy(t.rightPathCache[h][:], currentChildHash[:]) + leftIsFilled = false + } + var child common.Hash + copy(child[:], currentChildHash[:]) + parent = treeNode{ + left: child, + right: common.Hash{}, + } + } + currentChildHash = parent.hash() + newNodes = append(newNodes, parent) + } + + // store root + root := currentChildHash + // store nodes + + t.lastIndex++ + return nil +} + +// TODO: handle rerog: lastIndex & rightPathCache