Skip to content

Commit

Permalink
[NONEVM-714] [solana] - Add multiple blocks aggregation functionality…
Browse files Browse the repository at this point in the history
… to Block History Estimator (#896)

* multiple blocks history estimator

* comment fix

* fix txm tests

* fix internal tests

* fix test

* fix internal test

* fix dataraces

* solve data race

* solve data races

* tiimeouut

* remove noisy logs

* fix data races

* fix races

* simplify tests

* reduce blocks file

* rename blockHistoryDepth to blockHistorySize

* remove estimation method, refactor config and tests

* fix typo

* remove eventually from multiple blocks estimator tests

* improve tests and reduce helper block files

* err at initialization + dedup tests

* add logs and skip when no relevant txs found

* fix log

* avg of medians

* fix lint ci failing

* order of fields in config matters

* nits

* use top level context in tests

* prevent underlying base changing when bumping

* prepare for config changes

* Revert "prepare for config changes"

This reverts commit 213f7bc.

* Revert "prevent underlying base changing when bumping"

This reverts commit fc205d0.

* keep blockHistorySize near BlockHistoryPollPeriod
  • Loading branch information
Farber98 authored Nov 4, 2024
1 parent 1cf95ab commit 39cabce
Show file tree
Hide file tree
Showing 12 changed files with 1,402 additions and 118,746 deletions.
34 changes: 33 additions & 1 deletion pkg/solana/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import (

"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/rpc"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
"golang.org/x/sync/singleflight"

"github.com/smartcontractkit/chainlink-common/pkg/logger"

mn "github.com/smartcontractkit/chainlink-solana/pkg/solana/client/multinode"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/config"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/monitor"
Expand All @@ -36,6 +37,8 @@ type Reader interface {
ChainID(ctx context.Context) (mn.StringID, error)
GetFeeForMessage(ctx context.Context, msg string) (uint64, error)
GetLatestBlock(ctx context.Context) (*rpc.GetBlockResult, error)
GetBlocksWithLimit(ctx context.Context, startSlot uint64, limit uint64) (*rpc.BlocksResult, error)
GetBlock(ctx context.Context, slot uint64) (*rpc.GetBlockResult, error)
}

// AccountReader is an interface that allows users to pass either the solana rpc client or the relay client
Expand Down Expand Up @@ -275,3 +278,32 @@ func (c *Client) GetLatestBlock(ctx context.Context) (*rpc.GetBlockResult, error
})
return v.(*rpc.GetBlockResult), err
}

func (c *Client) GetBlock(ctx context.Context, slot uint64) (*rpc.GetBlockResult, error) {
// get block based on slot
done := c.latency("get_block")
defer done()
ctx, cancel := context.WithTimeout(ctx, c.txTimeout)
defer cancel()
v, err, _ := c.requestGroup.Do("GetBlockWithOpts", func() (interface{}, error) {
version := uint64(0) // pull all tx types (legacy + v0)
return c.rpc.GetBlockWithOpts(ctx, slot, &rpc.GetBlockOpts{
Commitment: c.commitment,
MaxSupportedTransactionVersion: &version,
})
})
return v.(*rpc.GetBlockResult), err
}

func (c *Client) GetBlocksWithLimit(ctx context.Context, startSlot uint64, limit uint64) (*rpc.BlocksResult, error) {
done := c.latency("get_blocks_with_limit")
defer done()

ctx, cancel := context.WithTimeout(ctx, c.txTimeout)
defer cancel()

v, err, _ := c.requestGroup.Do("GetBlocksWithLimit", func() (interface{}, error) {
return c.rpc.GetBlocksWithLimit(ctx, startSlot, limit, c.commitment)
})
return v.(*rpc.BlocksResult), err
}
30 changes: 30 additions & 0 deletions pkg/solana/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,36 @@ func TestClient_Reader_Integration(t *testing.T) {
assert.NotEqual(t, solana.Hash{}, block.Blockhash)
assert.NotEqual(t, uint64(0), block.ParentSlot)
assert.NotEqual(t, uint64(0), block.ParentSlot)

// GetBlock
// Test fetching a valid block
block, err = c.GetBlock(ctx, slot0)
assert.NoError(t, err)
assert.NotNil(t, block)
assert.Equal(t, slot0, block.ParentSlot+1)
assert.NotEqual(t, solana.Hash{}, block.Blockhash)

// Test fetching a block with an invalid future slot
futureSlot := slot0 + 1000000
block, err = c.GetBlock(ctx, futureSlot)
assert.Error(t, err)
assert.Nil(t, block)

// GetBlocksWithLimit
// Define the limit of blocks to fetch and calculate the start slot
limit := uint64(10)
startSlot := slot0 - limit + 1

// Fetch blocks with limit
blocksResult, err := c.GetBlocksWithLimit(ctx, startSlot, limit)
assert.NoError(t, err)
assert.NotNil(t, blocksResult)

// Verify that the slots returned are within the expected range
for _, slot := range *blocksResult {
assert.GreaterOrEqual(t, slot, startSlot)
assert.LessOrEqual(t, slot, slot0)
}
}

func TestClient_Reader_ChainID(t *testing.T) {
Expand Down
60 changes: 60 additions & 0 deletions pkg/solana/client/mocks/ReaderWriter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions pkg/solana/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var defaultConfigSet = Chain{
ComputeUnitPriceDefault: ptr(uint64(0)),
FeeBumpPeriod: config.MustNewDuration(3 * time.Second), // set to 0 to disable fee bumping
BlockHistoryPollPeriod: config.MustNewDuration(5 * time.Second),
BlockHistorySize: ptr(uint64(1)), // 1: uses latest block; >1: Uses multiple blocks, where n is number of blocks. DISCLAIMER: 1:1 ratio between n and RPC calls.
ComputeUnitLimitDefault: ptr(uint32(200_000)), // set to 0 to disable adding compute unit limit
EstimateComputeUnitLimit: ptr(false), // set to false to disable compute unit limit estimation
}
Expand All @@ -53,6 +54,7 @@ type Config interface {
ComputeUnitPriceDefault() uint64
FeeBumpPeriod() time.Duration
BlockHistoryPollPeriod() time.Duration
BlockHistorySize() uint64
ComputeUnitLimitDefault() uint32
EstimateComputeUnitLimit() bool
}
Expand All @@ -74,6 +76,7 @@ type Chain struct {
ComputeUnitPriceDefault *uint64
FeeBumpPeriod *config.Duration
BlockHistoryPollPeriod *config.Duration
BlockHistorySize *uint64
ComputeUnitLimitDefault *uint32
EstimateComputeUnitLimit *bool
}
Expand Down Expand Up @@ -127,6 +130,9 @@ func (c *Chain) SetDefaults() {
if c.BlockHistoryPollPeriod == nil {
c.BlockHistoryPollPeriod = defaultConfigSet.BlockHistoryPollPeriod
}
if c.BlockHistorySize == nil {
c.BlockHistorySize = defaultConfigSet.BlockHistorySize
}
if c.ComputeUnitLimitDefault == nil {
c.ComputeUnitLimitDefault = defaultConfigSet.ComputeUnitLimitDefault
}
Expand Down
18 changes: 18 additions & 0 deletions pkg/solana/config/mocks/config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions pkg/solana/config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ func setFromChain(c, f *Chain) {
if f.BlockHistoryPollPeriod != nil {
c.BlockHistoryPollPeriod = f.BlockHistoryPollPeriod
}
if f.BlockHistorySize != nil {
c.BlockHistorySize = f.BlockHistorySize
}
}

func (c *TOMLConfig) ValidateConfig() (err error) {
Expand Down Expand Up @@ -278,6 +281,10 @@ func (c *TOMLConfig) BlockHistoryPollPeriod() time.Duration {
return c.Chain.BlockHistoryPollPeriod.Duration()
}

func (c *TOMLConfig) BlockHistorySize() uint64 {
return *c.Chain.BlockHistorySize
}

func (c *TOMLConfig) ComputeUnitLimitDefault() uint32 {
return *c.Chain.ComputeUnitLimitDefault
}
Expand Down
Loading

0 comments on commit 39cabce

Please sign in to comment.