Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement v9/v10 #698

Merged
merged 68 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
c483301
Initial ssz spec
jshufro Apr 12, 2024
f3ac3a7
Add SSZ and JSON interop
jshufro Apr 14, 2024
573d1e0
Add tests for rewards ssz
jshufro Apr 19, 2024
012023b
Add v9 as a copy of v8 with renames
jshufro May 5, 2024
36aecfb
Bump non-struct-8s
jshufro May 5, 2024
33263bb
Return serialized json after writing rewards files to disk
jshufro May 5, 2024
08e4a69
Parameterize rewards file extension
jshufro May 5, 2024
57e73e6
Rename paths to specify format
jshufro May 6, 2024
c0c23fc
treegen implementations save rewards files
jshufro May 19, 2024
ba4d7e4
Schedule v9 for holesky and mainnet
jshufro May 19, 2024
ab9d920
Implement stateless v9
jshufro May 20, 2024
9f4c292
Deduplicate some rewards tree structures
jshufro May 21, 2024
c4f985d
Fix some small bugs
jshufro May 21, 2024
fc0f79e
Move invalidNetworkRewards out of rewards file
jshufro May 21, 2024
1145d52
Remove InvalidNetworkNodes from the tree file, return it instead
jshufro May 21, 2024
02382d0
Return MinipoolPerformanceFile in GenerateTreeResult instead of overl…
jshufro May 21, 2024
26b9d76
Delete IRewardsFile GetHeader function
jshufro May 21, 2024
71b682e
Remove INodeRewardsInfo interface
jshufro May 22, 2024
6afeb98
Delete IRewardsFile GetNetworkRewards function
jshufro May 22, 2024
bd9974e
Allow RewardsFile v3 and SSZFile v1 to be saved. Ensure SSZFile v1 co…
jshufro May 22, 2024
b7eff7b
Switch underlying ssz bigint type to math/big.Int and only convert to…
jshufro May 23, 2024
63d1490
Clarifications around the term Network in SSZFile_v1
jshufro May 23, 2024
dbe270e
Add constructors for NodeReward/NetworkReward
jshufro Jun 18, 2024
80799e0
Use SSZFile_v1 in treegen v9
jshufro May 23, 2024
2d73b45
Implement rolling v9
jshufro Jun 18, 2024
b1deefe
Use SSZFile_v1 in treegen rolling v9
jshufro Jun 18, 2024
d364450
Remove RocketPoolConfig dependency from treegen
jshufro Sep 24, 2024
be0c973
Create interface for rp rewards execution functions to support future…
jshufro Sep 25, 2024
29f5fb9
Add json decorators for NetworkState serialization
jshufro Sep 26, 2024
d943791
Simplify NetworkState and StateManager
jshufro Sep 26, 2024
a4483c7
Add cli utility for serializing NetworkState at a given slot
jshufro Sep 26, 2024
e51996d
Add beacon client interface to rewards for dependency injection
jshufro Sep 28, 2024
29be49f
Support recording critical duties slots for validators who opted in, …
jshufro Oct 7, 2024
cfb2d63
Add generator v8 mainnet unit test
jshufro Oct 7, 2024
4042c8c
Update CalculateAverageFeeAndDistributorShares to have a test-friendl…
jshufro Oct 8, 2024
ad9376e
Add mock interval tests
jshufro Oct 9, 2024
bd398dd
Rename v9 generators to include v10
jshufro Oct 20, 2024
91ffd13
Update calculations to remove rpip-30 phase-in from v9v10
jshufro Oct 20, 2024
d1a7b20
Remove hard-coding of max effective stake for rpip30 logic
jshufro Oct 20, 2024
76a105a
Add withdrawals to beacon block getter
jshufro Oct 20, 2024
3cd0c4f
Use beacon blocks instead of attestation endpoint for v9v10 performan…
jshufro Oct 20, 2024
0e35769
Add Balance queries to beacon client
jshufro Oct 28, 2024
92070b8
Implement v10 stateless
jshufro Oct 28, 2024
28dbb56
Make RewardsExecutionClient pure
jshufro Nov 1, 2024
e38215f
Implement v10 logic for rolling
jshufro Nov 3, 2024
17e8abe
Make rolling manager dependency-injection friendly
jshufro Nov 5, 2024
0511b6d
Fix some eligibility bugs
jshufro Nov 12, 2024
a0aa5a6
Fix fee calculation to account for bonus commission, update RR to be …
jshufro Nov 12, 2024
981cefb
Add backoff to validator balance queries for treegen
jshufro Nov 20, 2024
5f238b3
Make the beacon node balance queries serial, since they're so slow an…
jshufro Nov 20, 2024
35f2353
Rename getDuties to duringInterval, don't get withdrawals from blocks…
jshufro Nov 21, 2024
5bf5d7a
Fix bug where RR processed withdrawals after record end
jshufro Nov 21, 2024
557b870
Remove balance queries from v10, fix some bugs
jshufro Nov 22, 2024
587a590
Update v10 tests
jshufro Nov 22, 2024
cfa8704
Set v10 interval consts
jshufro Nov 22, 2024
7ee7750
Update rocketpool-go go.mod
jshufro Nov 22, 2024
9817ab5
Merge branch 'master' into jms/v10
jshufro Nov 23, 2024
437a03c
Add tests to check against full withdrawals
jshufro Nov 23, 2024
157ca6f
Only count excess balance in full withdrawals
jshufro Nov 23, 2024
7b251ff
Preallocate some beacon block vectors
jshufro Nov 24, 2024
eae26d9
Fix concurrent map access
jshufro Nov 25, 2024
b47a29b
Add nilcheck to commission scale in event of insufficient sp balance
jshufro Nov 25, 2024
6503067
Precompute EligibleBorrowedEth and cache RplStake
jshufro Nov 26, 2024
06fcc7f
Merge pull request #11 from jshufro/jms/v10-opt
jshufro Nov 26, 2024
102a83f
respect slot deadlines for attestations
jshufro Nov 26, 2024
5f017d7
Remove rolling records
jshufro Nov 29, 2024
fa1e8d3
Add committeeData.Release to reduce allocations
jshufro Dec 5, 2024
534ef12
Bump test timeout
jshufro Dec 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ jobs:
- uses: actions/setup-go@v4
with:
go-version: 1.21.8
- run: go test ./...
- run: go test ./... -timeout 30m
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/goccy/go-json v0.10.2
github.com/google/uuid v1.5.0
github.com/hashicorp/go-version v1.6.0
github.com/holiman/uint256 v1.2.4
github.com/ipfs/boxo v0.8.0
github.com/ipfs/go-cid v0.4.1
github.com/ipfs/go-datastore v0.6.0
Expand All @@ -32,7 +33,7 @@ require (
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7
github.com/prysmaticlabs/prysm/v5 v5.0.3
github.com/rivo/tview v0.0.0-20230208211350-7dfff1ce7854
github.com/rocket-pool/rocketpool-go v1.8.4-0.20241009143357-7b6894d57365
github.com/rocket-pool/rocketpool-go v1.8.4-0.20241122223132-c5f2be18f72b
github.com/sethvargo/go-password v0.2.0
github.com/shirou/gopsutil/v3 v3.23.1
github.com/tyler-smith/go-bip39 v1.1.0
Expand Down Expand Up @@ -87,7 +88,6 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 // indirect
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/herumi/bls-eth-go-binary v1.28.1 // indirect
github.com/holiman/uint256 v1.2.4 // indirect
github.com/ipfs/bbloom v0.0.4 // indirect
github.com/ipfs/go-bitfield v1.1.0 // indirect
github.com/ipfs/go-block-format v0.1.2 // indirect
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -633,10 +633,8 @@ github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rocket-pool/go-merkletree v1.0.1-0.20220406020931-c262d9b976dd h1:p9KuetSKB9nte9I/MkkiM3pwKFVQgqxxPTQ0y56Ff6s=
github.com/rocket-pool/go-merkletree v1.0.1-0.20220406020931-c262d9b976dd/go.mod h1:UE9fof8P7iESVtLn1K9CTSkNRYVFHZHlf96RKbU33kA=
github.com/rocket-pool/rocketpool-go v1.8.4-0.20240903025128-025f78ebda85 h1:sCeOQE95E9KATbaz9rnHezLvZnJa0FdNp+kE7cwogSI=
github.com/rocket-pool/rocketpool-go v1.8.4-0.20240903025128-025f78ebda85/go.mod h1:f2TVsMOYmCwaJOhshG2zRoX89PZmvCkCD7UYJ9waRkI=
github.com/rocket-pool/rocketpool-go v1.8.4-0.20241009143357-7b6894d57365 h1:e8Y0PxBCpIV0NhCM2VvuceNbGSMfLagbMhcfwBzCNNc=
github.com/rocket-pool/rocketpool-go v1.8.4-0.20241009143357-7b6894d57365/go.mod h1:f2TVsMOYmCwaJOhshG2zRoX89PZmvCkCD7UYJ9waRkI=
github.com/rocket-pool/rocketpool-go v1.8.4-0.20241122223132-c5f2be18f72b h1:PnL2c1StqHDOjyOUYn4C/tuwhLtIZ2N/3qfNYyQlVWc=
github.com/rocket-pool/rocketpool-go v1.8.4-0.20241122223132-c5f2be18f72b/go.mod h1:f2TVsMOYmCwaJOhshG2zRoX89PZmvCkCD7UYJ9waRkI=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
Expand Down
6 changes: 3 additions & 3 deletions rocketpool/api/network/generate-tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"os"

"github.com/fatih/color"
"github.com/rocket-pool/rocketpool-go/rewards"
"github.com/rocket-pool/smartnode/shared/services"
"github.com/rocket-pool/smartnode/shared/services/config"
"github.com/rocket-pool/smartnode/shared/types/api"
"github.com/urfave/cli"
)
Expand All @@ -32,14 +32,14 @@ func canGenerateRewardsTree(c *cli.Context, index uint64) (*api.CanNetworkGenera
response := api.CanNetworkGenerateRewardsTreeResponse{}

// Get the current interval
currentIndexBig, err := rewards.GetRewardIndex(rp, nil)
currentIndexBig, err := rp.GetRewardIndex(nil)
if err != nil {
return nil, err
}
response.CurrentIndex = currentIndexBig.Uint64()

// Get the path of the file to save
filePath := cfg.Smartnode.GetRewardsTreePath(index, true)
filePath := cfg.Smartnode.GetRewardsTreePath(index, true, config.RewardsExtensionJSON)
_, err = os.Stat(filePath)
if os.IsNotExist(err) {
response.TreeFileExists = false
Expand Down
7 changes: 5 additions & 2 deletions rocketpool/node/collectors/node-collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,10 @@ func (collector *NodeCollector) Collect(channel chan<- prometheus.Metric) {
if !previousInterval.TreeFileExists {
return fmt.Errorf("Error retrieving previous interval's total node weight: rewards file %s doesn't exist for interval %d", previousInterval.TreeFilePath, previousRewardIndex)
}
// Convert to a float, accuracy loss is meaningless compared to the heuristic's natural inaccuracy.
previousIntervalTotalNodeWeight = &previousInterval.TotalNodeWeight.Int

if previousInterval.TotalNodeWeight != nil {
previousIntervalTotalNodeWeight.Set(previousInterval.TotalNodeWeight)
}

// Get the info for each claimed interval
for _, claimedInterval := range claimed {
Expand Down Expand Up @@ -533,6 +535,7 @@ func (collector *NodeCollector) Collect(channel chan<- prometheus.Metric) {

nodeWeightSum := big.NewInt(0).Add(nodeWeight, previousIntervalTotalNodeWeight)

// Convert to a float, accuracy loss is meaningless compared to the heuristic's natural inaccuracy.
// nodeWeightRatio = current_node_weight / (current_node_weight + previous_interval_total_node_weight)
nodeWeightRatio, _ := big.NewFloat(0).Quo(
big.NewFloat(0).SetInt(nodeWeight),
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/node/download-reward-trees.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (d *downloadRewardsTrees) run(state *state.NetworkState) error {
missingIntervals := []uint64{}
for i := uint64(0); i < currentIndex; i++ {
// Check if the tree file exists
treeFilePath := d.cfg.Smartnode.GetRewardsTreePath(i, true)
treeFilePath := d.cfg.Smartnode.GetRewardsTreePath(i, true, config.RewardsExtensionJSON)
_, err = os.Stat(treeFilePath)
if os.IsNotExist(err) {
d.log.Printlnf("You are missing the rewards tree file for interval %d.", i)
Expand Down
5 changes: 1 addition & 4 deletions rocketpool/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,7 @@ func run(c *cli.Context) error {
updateLog := log.NewColorLogger(UpdateColor)

// Create the state manager
m, err := state.NewNetworkStateManager(rp, cfg, rp.Client, bc, &updateLog)
if err != nil {
return err
}
m := state.NewNetworkStateManager(rp, cfg.Smartnode.GetStateManagerContracts(), bc, &updateLog)
stateLocker := collectors.NewStateLocker()

// Initialize tasks
Expand Down
68 changes: 33 additions & 35 deletions rocketpool/watchtower/generate-rewards-tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,13 @@ func (t *generateRewardsTree) generateRewardsTree(index uint64) {
generationPrefix := fmt.Sprintf("[Interval %d Tree]", index)
t.log.Printlnf("%s Starting generation of Merkle rewards tree for interval %d.", generationPrefix, index)

// Get previous rewards pool addresses
previousRewardsPoolAddresses := t.cfg.Smartnode.GetPreviousRewardsPoolAddresses()

rewardsClient := rprewards.NewRewardsExecutionClient(t.rp)

// Find the event for this interval
rewardsEvent, err := rprewards.GetRewardSnapshotEvent(t.rp, t.cfg, index, nil)
rewardsEvent, err := rewardsClient.GetRewardSnapshotEvent(previousRewardsPoolAddresses, index, nil)
if err != nil {
t.handleError(fmt.Errorf("%s Error getting event for interval %d: %w", generationPrefix, index, err))
return
Expand All @@ -164,11 +169,7 @@ func (t *generateRewardsTree) generateRewardsTree(index uint64) {
address, err := client.RocketStorage.GetAddress(opts, crypto.Keccak256Hash([]byte("contract.addressrocketTokenRETH")))
if err == nil {
// Create the state manager with using the primary or fallback (not necessarily archive) EC
stateManager, err = state.NewNetworkStateManager(client, t.cfg, t.rp.Client, t.bc, &t.log)
if err != nil {
t.handleError(fmt.Errorf("error creating new NetworkStateManager with Archive EC: %w", err))
return
}
stateManager = state.NewNetworkStateManager(client, t.cfg.Smartnode.GetStateManagerContracts(), t.bc, &t.log)
} else {
// Check if an Archive EC is provided, and if using it would potentially resolve the error
errMessage := err.Error()
Expand Down Expand Up @@ -199,12 +200,16 @@ func (t *generateRewardsTree) generateRewardsTree(index uint64) {
t.handleError(fmt.Errorf("Error verifying rETH address with Archive EC: %w", err))
return
}
// Create the state manager with the archive EC
stateManager, err = state.NewNetworkStateManager(client, t.cfg, ec, t.bc, &t.log)

// Create a new rocketpool-go instance
archiveRP, err := rocketpool.NewRocketPool(ec, *t.rp.RocketStorageContract.Address)
if err != nil {
t.handleError(fmt.Errorf("Error creating new NetworkStateManager with ARchive EC: %w", err))
t.handleError(fmt.Errorf("Error instantiating client with Archive EC: %w", err))
return
}

// Create the state manager with the archive EC
stateManager = state.NewNetworkStateManager(archiveRP, t.cfg.Smartnode.GetStateManagerContracts(), t.bc, &t.log)
} else {
// No archive node specified
t.handleError(fmt.Errorf("***ERROR*** Primary EC cannot retrieve state for historical block %d and the Archive EC is not specified.", elBlockHeader.Number.Uint64()))
Expand Down Expand Up @@ -234,53 +239,46 @@ func (t *generateRewardsTree) generateRewardsTree(index uint64) {
// Implementation for rewards tree generation using a viable EC
func (t *generateRewardsTree) generateRewardsTreeImpl(rp *rocketpool.RocketPool, index uint64, generationPrefix string, rewardsEvent rewards.RewardsEvent, elBlockHeader *types.Header, state *state.NetworkState) {

// Determine the end of the interval
snapshotEnd := &rprewards.SnapshotEnd{
ConsensusBlock: rewardsEvent.ConsensusBlock.Uint64(),
ExecutionBlock: rewardsEvent.ExecutionBlock.Uint64(),
Slot: state.BeaconConfig.FirstSlotAtLeast(rewardsEvent.IntervalEndTime.Unix()),
}

// Generate the rewards file
start := time.Now()
treegen, err := rprewards.NewTreeGenerator(&t.log, generationPrefix, rp, t.cfg, t.bc, index, rewardsEvent.IntervalStartTime, rewardsEvent.IntervalEndTime, rewardsEvent.ConsensusBlock.Uint64(), elBlockHeader, rewardsEvent.IntervalsPassed.Uint64(), state, nil)
treegen, err := rprewards.NewTreeGenerator(&t.log, generationPrefix, rprewards.NewRewardsExecutionClient(rp), t.cfg, t.bc, index, rewardsEvent.IntervalStartTime, rewardsEvent.IntervalEndTime, snapshotEnd, elBlockHeader, rewardsEvent.IntervalsPassed.Uint64(), state)
if err != nil {
t.handleError(fmt.Errorf("%s Error creating Merkle tree generator: %w", generationPrefix, err))
return
}
rewardsFile, err := treegen.GenerateTree()
treeResult, err := treegen.GenerateTree()
if err != nil {
t.handleError(fmt.Errorf("%s Error generating Merkle tree: %w", generationPrefix, err))
return
}
header := rewardsFile.GetHeader()
for address, network := range header.InvalidNetworkNodes {
rewardsFile := treeResult.RewardsFile
for address, network := range treeResult.InvalidNetworkNodes {
t.log.Printlnf("%s WARNING: Node %s has invalid network %d assigned! Using 0 (mainnet) instead.", generationPrefix, address.Hex(), network)
}
t.log.Printlnf("%s Finished in %s", generationPrefix, time.Since(start).String())

// Validate the Merkle root
root := common.BytesToHash(header.MerkleTree.Root())
if root != rewardsEvent.MerkleRoot {
t.log.Printlnf("%s WARNING: your Merkle tree had a root of %s, but the canonical Merkle tree's root was %s. This file will not be usable for claiming rewards.", generationPrefix, root.Hex(), rewardsEvent.MerkleRoot.Hex())
root := rewardsFile.GetMerkleRoot()
if root != rewardsEvent.MerkleRoot.Hex() {
t.log.Printlnf("%s WARNING: your Merkle tree had a root of %s, but the canonical Merkle tree's root was %s. This file will not be usable for claiming rewards.", generationPrefix, root, rewardsEvent.MerkleRoot.Hex())
} else {
t.log.Printlnf("%s Your Merkle tree's root of %s matches the canonical root! You will be able to use this file for claiming rewards.", generationPrefix, header.MerkleRoot)
t.log.Printlnf("%s Your Merkle tree's root of %s matches the canonical root! You will be able to use this file for claiming rewards.", generationPrefix, root)
}

// Create the JSON files
rewardsFile.SetMinipoolPerformanceFileCID("---")

// Save the files
t.log.Printlnf("%s Saving JSON files...", generationPrefix)
localMinipoolPerformanceFile := rprewards.NewLocalFile[rprewards.IMinipoolPerformanceFile](
rewardsFile.GetMinipoolPerformanceFile(),
t.cfg.Smartnode.GetMinipoolPerformancePath(index, true),
)
localRewardsFile := rprewards.NewLocalFile[rprewards.IRewardsFile](
rewardsFile,
t.cfg.Smartnode.GetRewardsTreePath(index, true),
)

// Write the files
err = localMinipoolPerformanceFile.Write()
if err != nil {
t.handleError(fmt.Errorf("%s error saving minipool performance file: %w", generationPrefix, err))
return
}
err = localRewardsFile.Write()
_, _, err = treegen.SaveFiles(treeResult, false)
if err != nil {
t.handleError(fmt.Errorf("%s error saving rewards file: %w", generationPrefix, err))
t.handleError(fmt.Errorf("%s failed to save rewards artifacts: %w", generationPrefix, err))
return
}

Expand Down
13 changes: 8 additions & 5 deletions rocketpool/watchtower/submit-network-balances.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,7 @@ func (t *submitNetworkBalances) getNetworkBalances(elBlockHeader *types.Header,
}

// Create a new state gen manager
mgr, err := state.NewNetworkStateManager(client, t.cfg, client.Client, t.bc, t.log)
if err != nil {
return networkBalances{}, fmt.Errorf("error creating network state manager for EL block %s, Beacon slot %d: %w", elBlock, beaconBlock, err)
}
mgr := state.NewNetworkStateManager(client, t.cfg.Smartnode.GetStateManagerContracts(), t.bc, t.log)

// Create a new state for the target block
state, err := mgr.GetStateForSlot(beaconBlock)
Expand Down Expand Up @@ -352,10 +349,16 @@ func (t *submitNetworkBalances) getNetworkBalances(elBlockHeader *types.Header,
timeSinceStart := slotTime.Sub(startTime)
intervalsPassed := timeSinceStart / intervalTime
endTime := slotTime
// Since we aren't generating an actual tree, just use beaconBlock as the snapshotEnd
snapshotEnd := &rprewards.SnapshotEnd{
Slot: beaconBlock,
ConsensusBlock: beaconBlock,
ExecutionBlock: state.ElBlockNumber,
}

// Approximate the staker's share of the smoothing pool balance
// NOTE: this will use the "vanilla" variant of treegen, without rolling records, to retain parity with other Oracle DAO nodes that aren't using rolling records
treegen, err := rprewards.NewTreeGenerator(t.log, "[Balances]", client, t.cfg, t.bc, currentIndex, startTime, endTime, beaconBlock, elBlockHeader, uint64(intervalsPassed), state, nil)
treegen, err := rprewards.NewTreeGenerator(t.log, "[Balances]", rprewards.NewRewardsExecutionClient(client), t.cfg, t.bc, currentIndex, startTime, endTime, snapshotEnd, elBlockHeader, uint64(intervalsPassed), state)
if err != nil {
return fmt.Errorf("error creating merkle tree generator to approximate share of smoothing pool: %w", err)
}
Expand Down
Loading
Loading