From f31cc09117096ee1c4ea5af1a42cd1a687c2d0dd Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Thu, 19 Sep 2024 18:22:32 +0300 Subject: [PATCH 01/13] chore: Optimize receiptCommitment function for parallel processing --- core/receipt.go | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/core/receipt.go b/core/receipt.go index 0984118c28..203a4773bc 100644 --- a/core/receipt.go +++ b/core/receipt.go @@ -1,9 +1,13 @@ package core import ( + "runtime" + "sync" + "github.com/NethermindEth/juno/core/crypto" "github.com/NethermindEth/juno/core/felt" "github.com/NethermindEth/juno/core/trie" + "github.com/sourcegraph/conc/pool" ) type GasConsumed struct { @@ -62,14 +66,33 @@ func messagesSentHash(messages []*L2ToL1Message) *felt.Felt { func receiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) { var commitment *felt.Felt - return commitment, trie.RunOnTempTriePoseidon(commitmentTrieHeight, func(trie *trie.Trie) error { - for i, receipt := range receipts { - receiptTrieKey := new(felt.Felt).SetUint64(uint64(i)) - _, err := trie.Put(receiptTrieKey, receipt.hash()) - if err != nil { - return err - } + numWorkers := runtime.GOMAXPROCS(0) + receiptsPerWorker := max(1, len(receipts)/numWorkers) + workerPool := pool.New().WithErrors().WithMaxGoroutines(numWorkers) + var trieMutex sync.Mutex + + for receiptIdx := 0; receiptIdx < len(receipts); receiptIdx += receiptsPerWorker { + startIdx := receiptIdx + endIdx := min(startIdx+receiptsPerWorker, len(receipts)) + workerPool.Go(func() error { + for i, receipt := range receipts[startIdx:endIdx] { + receiptTrieKey := new(felt.Felt).SetUint64(uint64(receiptIdx + i)) + receiptHash := receipt.hash() + + trieMutex.Lock() + _, err := trie.Put(receiptTrieKey, receiptHash) + trieMutex.Unlock() + if err != nil { + return err + } + } + return nil + }) + } + + if err := workerPool.Wait(); err != nil { + return err } root, err := trie.Root() @@ -77,7 +100,6 @@ func receiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) { return err } commitment = root - return nil }) } From e93c680fd94688ddb3b5763abd6cb06c4b246aa3 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Fri, 20 Sep 2024 14:33:08 +0300 Subject: [PATCH 02/13] Optimize receiptCommitment function for parallel processing --- core/block.go | 2 +- core/receipt.go | 69 ++++++++++++++++++++++++++++------------ core/receipt_pkg_test.go | 31 ++++++++++++++++++ 3 files changed, 80 insertions(+), 22 deletions(-) create mode 100644 core/receipt_pkg_test.go diff --git a/core/block.go b/core/block.go index b11fa2a36e..c3cdd6f9b3 100644 --- a/core/block.go +++ b/core/block.go @@ -185,7 +185,7 @@ func Post0132Hash(b *Block, stateDiff *StateDiff) (*felt.Felt, *BlockCommitments eCommitment, eErr = eventCommitmentPoseidon(b.Receipts) }) wg.Go(func() { - rCommitment, rErr = receiptCommitment(b.Receipts) + rCommitment, rErr = ReceiptCommitment(b.Receipts) }) wg.Go(func() { diff --git a/core/receipt.go b/core/receipt.go index 203a4773bc..387fba6a02 100644 --- a/core/receipt.go +++ b/core/receipt.go @@ -7,7 +7,6 @@ import ( "github.com/NethermindEth/juno/core/crypto" "github.com/NethermindEth/juno/core/felt" "github.com/NethermindEth/juno/core/trie" - "github.com/sourcegraph/conc/pool" ) type GasConsumed struct { @@ -64,35 +63,62 @@ func messagesSentHash(messages []*L2ToL1Message) *felt.Felt { return crypto.PoseidonArray(chain...) } -func receiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) { +func ReceiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) { + type result struct { + key *felt.Felt + value *felt.Felt + } var commitment *felt.Felt return commitment, trie.RunOnTempTriePoseidon(commitmentTrieHeight, func(trie *trie.Trie) error { - numWorkers := runtime.GOMAXPROCS(0) - receiptsPerWorker := max(1, len(receipts)/numWorkers) - workerPool := pool.New().WithErrors().WithMaxGoroutines(numWorkers) + numWorkers := min(runtime.GOMAXPROCS(0), len(receipts)) + resultChan := make(chan result, len(receipts)) var trieMutex sync.Mutex - for receiptIdx := 0; receiptIdx < len(receipts); receiptIdx += receiptsPerWorker { - startIdx := receiptIdx - endIdx := min(startIdx+receiptsPerWorker, len(receipts)) - workerPool.Go(func() error { + errChan := make(chan error, numWorkers) + + var wg sync.WaitGroup + wg.Add(numWorkers) + + receiptsPerWorker := max(1, (len(receipts)+numWorkers-1)/numWorkers) + + for workerID := 0; workerID < numWorkers; workerID++ { + go func(id int) { + defer wg.Done() + startIdx := id * receiptsPerWorker + endIdx := min(startIdx+receiptsPerWorker, len(receipts)) + for i, receipt := range receipts[startIdx:endIdx] { - receiptTrieKey := new(felt.Felt).SetUint64(uint64(receiptIdx + i)) + receiptTrieKey := new(felt.Felt).SetUint64(uint64(startIdx + i)) receiptHash := receipt.hash() - - trieMutex.Lock() - _, err := trie.Put(receiptTrieKey, receiptHash) - trieMutex.Unlock() - if err != nil { - return err - } + resultChan <- result{receiptTrieKey, receiptHash} } - return nil - }) + + errChan <- nil + }(workerID) } - if err := workerPool.Wait(); err != nil { - return err + go func() { + wg.Wait() + close(resultChan) + }() + + go func() { + for result := range resultChan { + trieMutex.Lock() + _, err := trie.Put(result.key, result.value) + trieMutex.Unlock() + if err != nil { + errChan <- err + return + } + } + errChan <- nil + }() + + for i := 0; i < numWorkers+1; i++ { + if err := <-errChan; err != nil { + return err + } } root, err := trie.Root() @@ -100,6 +126,7 @@ func receiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) { return err } commitment = root + return nil }) } diff --git a/core/receipt_pkg_test.go b/core/receipt_pkg_test.go new file mode 100644 index 0000000000..d5e8dbcac0 --- /dev/null +++ b/core/receipt_pkg_test.go @@ -0,0 +1,31 @@ +package core_test + +import ( + "context" + "slices" + "testing" + + "github.com/NethermindEth/juno/clients/feeder" + "github.com/NethermindEth/juno/core" + adaptfeeder "github.com/NethermindEth/juno/starknetdata/feeder" + "github.com/NethermindEth/juno/utils" + "github.com/stretchr/testify/require" +) + +func getReceipts(b *testing.B, blockNum uint64) []*core.TransactionReceipt { + b.Helper() + client := feeder.NewClient(utils.Sepolia.FeederURL) + gw := adaptfeeder.New(client) + block, err := gw.BlockByNumber(context.Background(), blockNum) + require.NoError(b, err) + + return slices.Repeat(block.Receipts, 100) +} + +func BenchmarkReceiptCommitment(b *testing.B) { + receipts := getReceipts(b, 35748) + b.ResetTimer() + for i := 0; i < b.N; i++ { + core.ReceiptCommitment(receipts) + } +} From 2fcfa31c57bee2e3801a9e51ca84523a79900007 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Fri, 20 Sep 2024 14:39:10 +0300 Subject: [PATCH 03/13] Fix linter --- core/receipt_pkg_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/receipt_pkg_test.go b/core/receipt_pkg_test.go index d5e8dbcac0..77b54fb9c3 100644 --- a/core/receipt_pkg_test.go +++ b/core/receipt_pkg_test.go @@ -26,6 +26,7 @@ func BenchmarkReceiptCommitment(b *testing.B) { receipts := getReceipts(b, 35748) b.ResetTimer() for i := 0; i < b.N; i++ { - core.ReceiptCommitment(receipts) + _, err := core.ReceiptCommitment(receipts) + require.NoError(b, err) } } From b31d2d94dd81a46e211ae87d209ac340dc7a1f14 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Fri, 20 Sep 2024 16:07:00 +0300 Subject: [PATCH 04/13] Optimize receiptCommitment function for parallel processing --- core/receipt.go | 59 ++++++++++++++----------------------------------- 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/core/receipt.go b/core/receipt.go index 387fba6a02..fb70e51231 100644 --- a/core/receipt.go +++ b/core/receipt.go @@ -64,59 +64,34 @@ func messagesSentHash(messages []*L2ToL1Message) *felt.Felt { } func ReceiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) { - type result struct { - key *felt.Felt - value *felt.Felt - } var commitment *felt.Felt return commitment, trie.RunOnTempTriePoseidon(commitmentTrieHeight, func(trie *trie.Trie) error { numWorkers := min(runtime.GOMAXPROCS(0), len(receipts)) - resultChan := make(chan result, len(receipts)) - var trieMutex sync.Mutex - - errChan := make(chan error, numWorkers) - - var wg sync.WaitGroup + results := make([]*felt.Felt, len(receipts)) + wg := sync.WaitGroup{} wg.Add(numWorkers) - receiptsPerWorker := max(1, (len(receipts)+numWorkers-1)/numWorkers) + jobs := make(chan int, len(receipts)) + for i := range receipts { + jobs <- i + } + close(jobs) - for workerID := 0; workerID < numWorkers; workerID++ { - go func(id int) { + for range numWorkers { + go func() { defer wg.Done() - startIdx := id * receiptsPerWorker - endIdx := min(startIdx+receiptsPerWorker, len(receipts)) - - for i, receipt := range receipts[startIdx:endIdx] { - receiptTrieKey := new(felt.Felt).SetUint64(uint64(startIdx + i)) - receiptHash := receipt.hash() - resultChan <- result{receiptTrieKey, receiptHash} + for i := range jobs { + results[i] = receipts[i].hash() } - - errChan <- nil - }(workerID) + }() } - go func() { - wg.Wait() - close(resultChan) - }() - - go func() { - for result := range resultChan { - trieMutex.Lock() - _, err := trie.Put(result.key, result.value) - trieMutex.Unlock() - if err != nil { - errChan <- err - return - } - } - errChan <- nil - }() + wg.Wait() - for i := 0; i < numWorkers+1; i++ { - if err := <-errChan; err != nil { + key := new(felt.Felt) + for i, res := range results { + key.SetUint64(uint64(i)) + if _, err := trie.Put(key, res); err != nil { return err } } From 5836038af69a5e74bfe86a66da33ca625f2febd8 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Fri, 20 Sep 2024 16:11:31 +0300 Subject: [PATCH 05/13] Remove benchmark --- core/block.go | 2 +- core/receipt.go | 2 +- core/receipt_pkg_test.go | 32 -------------------------------- 3 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 core/receipt_pkg_test.go diff --git a/core/block.go b/core/block.go index c3cdd6f9b3..b11fa2a36e 100644 --- a/core/block.go +++ b/core/block.go @@ -185,7 +185,7 @@ func Post0132Hash(b *Block, stateDiff *StateDiff) (*felt.Felt, *BlockCommitments eCommitment, eErr = eventCommitmentPoseidon(b.Receipts) }) wg.Go(func() { - rCommitment, rErr = ReceiptCommitment(b.Receipts) + rCommitment, rErr = receiptCommitment(b.Receipts) }) wg.Go(func() { diff --git a/core/receipt.go b/core/receipt.go index fb70e51231..9de2ad9104 100644 --- a/core/receipt.go +++ b/core/receipt.go @@ -63,7 +63,7 @@ func messagesSentHash(messages []*L2ToL1Message) *felt.Felt { return crypto.PoseidonArray(chain...) } -func ReceiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) { +func receiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) { var commitment *felt.Felt return commitment, trie.RunOnTempTriePoseidon(commitmentTrieHeight, func(trie *trie.Trie) error { numWorkers := min(runtime.GOMAXPROCS(0), len(receipts)) diff --git a/core/receipt_pkg_test.go b/core/receipt_pkg_test.go deleted file mode 100644 index 77b54fb9c3..0000000000 --- a/core/receipt_pkg_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package core_test - -import ( - "context" - "slices" - "testing" - - "github.com/NethermindEth/juno/clients/feeder" - "github.com/NethermindEth/juno/core" - adaptfeeder "github.com/NethermindEth/juno/starknetdata/feeder" - "github.com/NethermindEth/juno/utils" - "github.com/stretchr/testify/require" -) - -func getReceipts(b *testing.B, blockNum uint64) []*core.TransactionReceipt { - b.Helper() - client := feeder.NewClient(utils.Sepolia.FeederURL) - gw := adaptfeeder.New(client) - block, err := gw.BlockByNumber(context.Background(), blockNum) - require.NoError(b, err) - - return slices.Repeat(block.Receipts, 100) -} - -func BenchmarkReceiptCommitment(b *testing.B) { - receipts := getReceipts(b, 35748) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err := core.ReceiptCommitment(receipts) - require.NoError(b, err) - } -} From 21079aef48692cd487e0cf6b1652a305e4d91472 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Mon, 23 Sep 2024 11:37:43 +0300 Subject: [PATCH 06/13] Rely on zero value: `var wg sync.WaitGroup` --- core/receipt.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/receipt.go b/core/receipt.go index 9de2ad9104..615b12aebc 100644 --- a/core/receipt.go +++ b/core/receipt.go @@ -68,7 +68,7 @@ func receiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) { return commitment, trie.RunOnTempTriePoseidon(commitmentTrieHeight, func(trie *trie.Trie) error { numWorkers := min(runtime.GOMAXPROCS(0), len(receipts)) results := make([]*felt.Felt, len(receipts)) - wg := sync.WaitGroup{} + var wg sync.WaitGroup wg.Add(numWorkers) jobs := make(chan int, len(receipts)) From 3443cc9d91f08817836dec21ff1ec92afafc588f Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Mon, 23 Sep 2024 11:38:43 +0300 Subject: [PATCH 07/13] Create new key for every result --- core/receipt.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/receipt.go b/core/receipt.go index 615b12aebc..b6565f23fd 100644 --- a/core/receipt.go +++ b/core/receipt.go @@ -88,9 +88,8 @@ func receiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) { wg.Wait() - key := new(felt.Felt) for i, res := range results { - key.SetUint64(uint64(i)) + key := new(felt.Felt).SetUint64(uint64(i)) if _, err := trie.Put(key, res); err != nil { return err } From 974dd84c473a231010a653e7380c0483299fa521 Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 23 Sep 2024 14:48:33 +0400 Subject: [PATCH 08/13] Add test --- core/receipt_pkg_test.go | 96 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 core/receipt_pkg_test.go diff --git a/core/receipt_pkg_test.go b/core/receipt_pkg_test.go new file mode 100644 index 0000000000..268d5eab59 --- /dev/null +++ b/core/receipt_pkg_test.go @@ -0,0 +1,96 @@ +package core + +import ( + "testing" + + "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/juno/utils" + "github.com/stretchr/testify/require" + "slices" +) + +func BenchmarkReceiptCommitment(b *testing.B) { + fromHex := func(hex string) *felt.Felt { + return utils.HexToFelt(b, hex) + } + // receipts were taken from sepolia block 35748 + baseReceipts := []*TransactionReceipt{ + { + TransactionHash: fromHex("0x5ac644bbd6ae98d3be2d988439854e33f0961e24f349a63b43e16d172bfe747"), + Fee: fromHex("0xd07af45c84550"), + Events: []*Event{ + { + From: fromHex("0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"), + Data: []*felt.Felt{ + fromHex("0x472aa8128e01eb0df145810c9511a92852d62a68ba8198ce5fa414e6337a365"), + fromHex("0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8"), + fromHex("0xd07af45c84550"), + fromHex("0x0"), + }, + Keys: []*felt.Felt{ + fromHex("0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"), + }, + }, + }, + ExecutionResources: &ExecutionResources{ + BuiltinInstanceCounter: BuiltinInstanceCounter{ + Pedersen: 16, + RangeCheck: 157, + Ecsda: 1, + Poseidon: 4, + }, + MemoryHoles: 0, + Steps: 3950, + DataAvailability: &DataAvailability{ + L1Gas: 0, + L1DataGas: 192, + }, + TotalGasConsumed: &GasConsumed{ + L1Gas: 117620, + L1DataGas: 192, + }, + }, + }, + { + Fee: fromHex("0x471426f16c4330"), + Events: []*Event{ + { + From: fromHex("0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"), + Data: []*felt.Felt{ + fromHex("0x472aa8128e01eb0df145810c9511a92852d62a68ba8198ce5fa414e6337a365"), + fromHex("0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8"), + fromHex("0x471426f16c4330"), + fromHex("0x0"), + }, + Keys: []*felt.Felt{ + fromHex("0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"), + }, + }, + }, + ExecutionResources: &ExecutionResources{ + BuiltinInstanceCounter: BuiltinInstanceCounter{ + Pedersen: 16, + RangeCheck: 157, + Ecsda: 1, + Poseidon: 4, + }, + Steps: 3950, + DataAvailability: &DataAvailability{ + L1Gas: 0, + L1DataGas: 192, + }, + TotalGasConsumed: &GasConsumed{ + L1Gas: 641644, + L1DataGas: 192, + }, + }, + TransactionHash: fromHex("0x21bc0afe54123b946855e1bf9389d943313df5c5c396fbf0630234a44f6f592"), + }, + } + receipts := slices.Repeat(baseReceipts, 100) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := receiptCommitment(receipts) + require.NoError(b, err) + } +} From d0737928917f20f49333ecb17c9063f88c20a666 Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 23 Sep 2024 14:49:31 +0400 Subject: [PATCH 09/13] Add comment to BenchmarkReceiptCommitment --- core/receipt_pkg_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/receipt_pkg_test.go b/core/receipt_pkg_test.go index 268d5eab59..dae383ab4c 100644 --- a/core/receipt_pkg_test.go +++ b/core/receipt_pkg_test.go @@ -14,6 +14,7 @@ func BenchmarkReceiptCommitment(b *testing.B) { return utils.HexToFelt(b, hex) } // receipts were taken from sepolia block 35748 + // we don't use adaptfeeder here because it causes cyclic import baseReceipts := []*TransactionReceipt{ { TransactionHash: fromHex("0x5ac644bbd6ae98d3be2d988439854e33f0961e24f349a63b43e16d172bfe747"), From e30e92a7e97be9976c4bc75d72181fbfc210f36a Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Mon, 23 Sep 2024 13:59:41 +0300 Subject: [PATCH 10/13] chore: Move slices import --- core/receipt_pkg_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/receipt_pkg_test.go b/core/receipt_pkg_test.go index dae383ab4c..0d0a1867bb 100644 --- a/core/receipt_pkg_test.go +++ b/core/receipt_pkg_test.go @@ -1,12 +1,12 @@ package core import ( + "slices" "testing" "github.com/NethermindEth/juno/core/felt" "github.com/NethermindEth/juno/utils" "github.com/stretchr/testify/require" - "slices" ) func BenchmarkReceiptCommitment(b *testing.B) { From e69cdab2e0d65eb2f51481b88fee70af73940bca Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 23 Sep 2024 15:00:20 +0400 Subject: [PATCH 11/13] Fix linter issue: gci in test --- core/receipt_pkg_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/receipt_pkg_test.go b/core/receipt_pkg_test.go index dae383ab4c..0d0a1867bb 100644 --- a/core/receipt_pkg_test.go +++ b/core/receipt_pkg_test.go @@ -1,12 +1,12 @@ package core import ( + "slices" "testing" "github.com/NethermindEth/juno/core/felt" "github.com/NethermindEth/juno/utils" "github.com/stretchr/testify/require" - "slices" ) func BenchmarkReceiptCommitment(b *testing.B) { From 9a100c6e18f023db6b99f553bba06479596fa2ed Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 23 Sep 2024 15:01:24 +0400 Subject: [PATCH 12/13] Added b.Helper() in fromHex() helper --- core/receipt_pkg_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/receipt_pkg_test.go b/core/receipt_pkg_test.go index 0d0a1867bb..2b86d83001 100644 --- a/core/receipt_pkg_test.go +++ b/core/receipt_pkg_test.go @@ -11,6 +11,7 @@ import ( func BenchmarkReceiptCommitment(b *testing.B) { fromHex := func(hex string) *felt.Felt { + b.Helper() return utils.HexToFelt(b, hex) } // receipts were taken from sepolia block 35748 From 454ef66fab1e0214bf3e0c1bafae93205434939f Mon Sep 17 00:00:00 2001 From: Daniil Ankushin Date: Mon, 23 Sep 2024 14:05:11 +0300 Subject: [PATCH 13/13] Rename `i` to `idx` Co-authored-by: Pawel Nowosielski Signed-off-by: Daniil Ankushin --- core/receipt.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/receipt.go b/core/receipt.go index b6565f23fd..66b0ed33d4 100644 --- a/core/receipt.go +++ b/core/receipt.go @@ -72,8 +72,8 @@ func receiptCommitment(receipts []*TransactionReceipt) (*felt.Felt, error) { wg.Add(numWorkers) jobs := make(chan int, len(receipts)) - for i := range receipts { - jobs <- i + for idx := range receipts { + jobs <- idx } close(jobs)