From 2ceac8303cb73ea04bdfb8cff908a2508877f752 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Thu, 31 Oct 2024 08:34:52 -0500 Subject: [PATCH 01/19] event loader with event watch and backfill --- .mockery.yaml | 9 + contracts/Anchor.toml | 29 +- contracts/Cargo.lock | 7 + .../generated/log_read_test/CreateLog.go | 146 +++++++ .../generated/log_read_test/CreateLog_test.go | 32 ++ contracts/generated/log_read_test/accounts.go | 3 + .../generated/log_read_test/instructions.go | 117 ++++++ .../generated/log_read_test/testing_utils.go | 20 + contracts/generated/log_read_test/types.go | 3 + contracts/programs/log-read-test/Cargo.toml | 19 + contracts/programs/log-read-test/Xargo.toml | 2 + contracts/programs/log-read-test/src/event.rs | 7 + contracts/programs/log-read-test/src/lib.rs | 25 ++ go.mod | 2 + go.sum | 2 + integration-tests/smoke/event_loader_test.go | 300 ++++++++++++++ pkg/solana/client/test_helpers.go | 29 +- pkg/solana/logpoller/job.go | 142 +++++++ pkg/solana/logpoller/loader.go | 265 ++++++++++++ pkg/solana/logpoller/loader_test.go | 289 +++++++++++++ pkg/solana/logpoller/mocks/parser.go | 81 ++++ pkg/solana/logpoller/mocks/rpc_client.go | 340 ++++++++++++++++ pkg/solana/logpoller/parser.go | 194 +++++++++ pkg/solana/logpoller/worker.go | 382 ++++++++++++++++++ pkg/solana/logpoller/worker_test.go | 196 +++++++++ 25 files changed, 2620 insertions(+), 21 deletions(-) create mode 100644 .mockery.yaml create mode 100644 contracts/generated/log_read_test/CreateLog.go create mode 100644 contracts/generated/log_read_test/CreateLog_test.go create mode 100644 contracts/generated/log_read_test/accounts.go create mode 100644 contracts/generated/log_read_test/instructions.go create mode 100644 contracts/generated/log_read_test/testing_utils.go create mode 100644 contracts/generated/log_read_test/types.go create mode 100644 contracts/programs/log-read-test/Cargo.toml create mode 100644 contracts/programs/log-read-test/Xargo.toml create mode 100644 contracts/programs/log-read-test/src/event.rs create mode 100644 contracts/programs/log-read-test/src/lib.rs create mode 100644 integration-tests/smoke/event_loader_test.go create mode 100644 pkg/solana/logpoller/job.go create mode 100644 pkg/solana/logpoller/loader.go create mode 100644 pkg/solana/logpoller/loader_test.go create mode 100644 pkg/solana/logpoller/mocks/parser.go create mode 100644 pkg/solana/logpoller/mocks/rpc_client.go create mode 100644 pkg/solana/logpoller/parser.go create mode 100644 pkg/solana/logpoller/worker.go create mode 100644 pkg/solana/logpoller/worker_test.go diff --git a/.mockery.yaml b/.mockery.yaml new file mode 100644 index 000000000..d9854e095 --- /dev/null +++ b/.mockery.yaml @@ -0,0 +1,9 @@ +dir: "{{ .InterfaceDir }}/mocks" +mockname: "{{ .InterfaceName }}" +outpkg: mocks +filename: "{{ .InterfaceName | snakecase }}.go" +packages: + github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller: + interfaces: + RPCClient: + Parser: \ No newline at end of file diff --git a/contracts/Anchor.toml b/contracts/Anchor.toml index 3611e1c0b..687e13a5a 100644 --- a/contracts/Anchor.toml +++ b/contracts/Anchor.toml @@ -1,26 +1,21 @@ -anchor_version = "0.29.0" +[toolchain] + +[features] +seeds = false +skip-lint = false + +[programs.localnet] +access_controller = "9xi644bRR8birboDGdTiwBq3C7VEeR7VuamRYYXCubUW" +log-read-test = "J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4" +ocr_2 = "cjg3oHmg9uuPsP8D6g29NWvhySJkdYdAo9D25PRbKXJ" +store = "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny" [registry] url = "https://anchor.projectserum.com" [provider] -cluster = "localnet" -# wallet = "~/.config/solana/id.json" +cluster = "Localnet" wallet = "id.json" [scripts] test = "pnpm run test" - -# [programs.mainnet] -# TODO: add pubkeys - -# [programs.testnet] -# TODO: add pubkeys - -# [programs.devnet] -# TODO: add pubkeys - -[programs.localnet] -ocr_2 = "cjg3oHmg9uuPsP8D6g29NWvhySJkdYdAo9D25PRbKXJ" # need to rename the idl to satisfy anchor.js... -store = "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny" -access_controller = "9xi644bRR8birboDGdTiwBq3C7VEeR7VuamRYYXCubUW" diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index ba4b5e1d7..953b2b81e 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -1214,6 +1214,13 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "log-read-test" +version = "0.1.0" +dependencies = [ + "anchor-lang", +] + [[package]] name = "memchr" version = "2.7.1" diff --git a/contracts/generated/log_read_test/CreateLog.go b/contracts/generated/log_read_test/CreateLog.go new file mode 100644 index 000000000..25a488ac7 --- /dev/null +++ b/contracts/generated/log_read_test/CreateLog.go @@ -0,0 +1,146 @@ +// Code generated by https://github.com/gagliardetto/anchor-go. DO NOT EDIT. + +package log_read_test + +import ( + "errors" + ag_binary "github.com/gagliardetto/binary" + ag_solanago "github.com/gagliardetto/solana-go" + ag_format "github.com/gagliardetto/solana-go/text/format" + ag_treeout "github.com/gagliardetto/treeout" +) + +// CreateLog is the `createLog` instruction. +type CreateLog struct { + Value *uint64 + + // [0] = [SIGNER] authority + // + // [1] = [] systemProgram + ag_solanago.AccountMetaSlice `bin:"-"` +} + +// NewCreateLogInstructionBuilder creates a new `CreateLog` instruction builder. +func NewCreateLogInstructionBuilder() *CreateLog { + nd := &CreateLog{ + AccountMetaSlice: make(ag_solanago.AccountMetaSlice, 2), + } + return nd +} + +// SetValue sets the "value" parameter. +func (inst *CreateLog) SetValue(value uint64) *CreateLog { + inst.Value = &value + return inst +} + +// SetAuthorityAccount sets the "authority" account. +func (inst *CreateLog) SetAuthorityAccount(authority ag_solanago.PublicKey) *CreateLog { + inst.AccountMetaSlice[0] = ag_solanago.Meta(authority).SIGNER() + return inst +} + +// GetAuthorityAccount gets the "authority" account. +func (inst *CreateLog) GetAuthorityAccount() *ag_solanago.AccountMeta { + return inst.AccountMetaSlice.Get(0) +} + +// SetSystemProgramAccount sets the "systemProgram" account. +func (inst *CreateLog) SetSystemProgramAccount(systemProgram ag_solanago.PublicKey) *CreateLog { + inst.AccountMetaSlice[1] = ag_solanago.Meta(systemProgram) + return inst +} + +// GetSystemProgramAccount gets the "systemProgram" account. +func (inst *CreateLog) GetSystemProgramAccount() *ag_solanago.AccountMeta { + return inst.AccountMetaSlice.Get(1) +} + +func (inst CreateLog) Build() *Instruction { + return &Instruction{BaseVariant: ag_binary.BaseVariant{ + Impl: inst, + TypeID: Instruction_CreateLog, + }} +} + +// ValidateAndBuild validates the instruction parameters and accounts; +// if there is a validation error, it returns the error. +// Otherwise, it builds and returns the instruction. +func (inst CreateLog) ValidateAndBuild() (*Instruction, error) { + if err := inst.Validate(); err != nil { + return nil, err + } + return inst.Build(), nil +} + +func (inst *CreateLog) Validate() error { + // Check whether all (required) parameters are set: + { + if inst.Value == nil { + return errors.New("Value parameter is not set") + } + } + + // Check whether all (required) accounts are set: + { + if inst.AccountMetaSlice[0] == nil { + return errors.New("accounts.Authority is not set") + } + if inst.AccountMetaSlice[1] == nil { + return errors.New("accounts.SystemProgram is not set") + } + } + return nil +} + +func (inst *CreateLog) EncodeToTree(parent ag_treeout.Branches) { + parent.Child(ag_format.Program(ProgramName, ProgramID)). + // + ParentFunc(func(programBranch ag_treeout.Branches) { + programBranch.Child(ag_format.Instruction("CreateLog")). + // + ParentFunc(func(instructionBranch ag_treeout.Branches) { + + // Parameters of the instruction: + instructionBranch.Child("Params[len=1]").ParentFunc(func(paramsBranch ag_treeout.Branches) { + paramsBranch.Child(ag_format.Param("Value", *inst.Value)) + }) + + // Accounts of the instruction: + instructionBranch.Child("Accounts[len=2]").ParentFunc(func(accountsBranch ag_treeout.Branches) { + accountsBranch.Child(ag_format.Meta(" authority", inst.AccountMetaSlice.Get(0))) + accountsBranch.Child(ag_format.Meta("systemProgram", inst.AccountMetaSlice.Get(1))) + }) + }) + }) +} + +func (obj CreateLog) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { + // Serialize `Value` param: + err = encoder.Encode(obj.Value) + if err != nil { + return err + } + return nil +} +func (obj *CreateLog) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { + // Deserialize `Value`: + err = decoder.Decode(&obj.Value) + if err != nil { + return err + } + return nil +} + +// NewCreateLogInstruction declares a new CreateLog instruction with the provided parameters and accounts. +func NewCreateLogInstruction( + // Parameters: + value uint64, + // Accounts: + authority ag_solanago.PublicKey, + systemProgram ag_solanago.PublicKey) *CreateLog { + return NewCreateLogInstructionBuilder(). + SetValue(value). + SetAuthorityAccount(authority). + SetSystemProgramAccount(systemProgram) +} diff --git a/contracts/generated/log_read_test/CreateLog_test.go b/contracts/generated/log_read_test/CreateLog_test.go new file mode 100644 index 000000000..e15524426 --- /dev/null +++ b/contracts/generated/log_read_test/CreateLog_test.go @@ -0,0 +1,32 @@ +// Code generated by https://github.com/gagliardetto/anchor-go. DO NOT EDIT. + +package log_read_test + +import ( + "bytes" + ag_gofuzz "github.com/gagliardetto/gofuzz" + ag_require "github.com/stretchr/testify/require" + "strconv" + "testing" +) + +func TestEncodeDecode_CreateLog(t *testing.T) { + fu := ag_gofuzz.New().NilChance(0) + for i := 0; i < 1; i++ { + t.Run("CreateLog"+strconv.Itoa(i), func(t *testing.T) { + { + params := new(CreateLog) + fu.Fuzz(params) + params.AccountMetaSlice = nil + buf := new(bytes.Buffer) + err := encodeT(*params, buf) + ag_require.NoError(t, err) + got := new(CreateLog) + err = decodeT(got, buf.Bytes()) + got.AccountMetaSlice = nil + ag_require.NoError(t, err) + ag_require.Equal(t, params, got) + } + }) + } +} diff --git a/contracts/generated/log_read_test/accounts.go b/contracts/generated/log_read_test/accounts.go new file mode 100644 index 000000000..981b967ad --- /dev/null +++ b/contracts/generated/log_read_test/accounts.go @@ -0,0 +1,3 @@ +// Code generated by https://github.com/gagliardetto/anchor-go. DO NOT EDIT. + +package log_read_test diff --git a/contracts/generated/log_read_test/instructions.go b/contracts/generated/log_read_test/instructions.go new file mode 100644 index 000000000..919528bbf --- /dev/null +++ b/contracts/generated/log_read_test/instructions.go @@ -0,0 +1,117 @@ +// Code generated by https://github.com/gagliardetto/anchor-go. DO NOT EDIT. + +package log_read_test + +import ( + "bytes" + "fmt" + ag_spew "github.com/davecgh/go-spew/spew" + ag_binary "github.com/gagliardetto/binary" + ag_solanago "github.com/gagliardetto/solana-go" + ag_text "github.com/gagliardetto/solana-go/text" + ag_treeout "github.com/gagliardetto/treeout" +) + +var ProgramID ag_solanago.PublicKey + +func SetProgramID(pubkey ag_solanago.PublicKey) { + ProgramID = pubkey + ag_solanago.RegisterInstructionDecoder(ProgramID, registryDecodeInstruction) +} + +const ProgramName = "LogReadTest" + +func init() { + if !ProgramID.IsZero() { + ag_solanago.RegisterInstructionDecoder(ProgramID, registryDecodeInstruction) + } +} + +var ( + Instruction_CreateLog = ag_binary.TypeID([8]byte{215, 95, 248, 114, 153, 204, 208, 48}) +) + +// InstructionIDToName returns the name of the instruction given its ID. +func InstructionIDToName(id ag_binary.TypeID) string { + switch id { + case Instruction_CreateLog: + return "CreateLog" + default: + return "" + } +} + +type Instruction struct { + ag_binary.BaseVariant +} + +func (inst *Instruction) EncodeToTree(parent ag_treeout.Branches) { + if enToTree, ok := inst.Impl.(ag_text.EncodableToTree); ok { + enToTree.EncodeToTree(parent) + } else { + parent.Child(ag_spew.Sdump(inst)) + } +} + +var InstructionImplDef = ag_binary.NewVariantDefinition( + ag_binary.AnchorTypeIDEncoding, + []ag_binary.VariantType{ + { + "create_log", (*CreateLog)(nil), + }, + }, +) + +func (inst *Instruction) ProgramID() ag_solanago.PublicKey { + return ProgramID +} + +func (inst *Instruction) Accounts() (out []*ag_solanago.AccountMeta) { + return inst.Impl.(ag_solanago.AccountsGettable).GetAccounts() +} + +func (inst *Instruction) Data() ([]byte, error) { + buf := new(bytes.Buffer) + if err := ag_binary.NewBorshEncoder(buf).Encode(inst); err != nil { + return nil, fmt.Errorf("unable to encode instruction: %w", err) + } + return buf.Bytes(), nil +} + +func (inst *Instruction) TextEncode(encoder *ag_text.Encoder, option *ag_text.Option) error { + return encoder.Encode(inst.Impl, option) +} + +func (inst *Instruction) UnmarshalWithDecoder(decoder *ag_binary.Decoder) error { + return inst.BaseVariant.UnmarshalBinaryVariant(decoder, InstructionImplDef) +} + +func (inst *Instruction) MarshalWithEncoder(encoder *ag_binary.Encoder) error { + err := encoder.WriteBytes(inst.TypeID.Bytes(), false) + if err != nil { + return fmt.Errorf("unable to write variant type: %w", err) + } + return encoder.Encode(inst.Impl) +} + +func registryDecodeInstruction(accounts []*ag_solanago.AccountMeta, data []byte) (interface{}, error) { + inst, err := DecodeInstruction(accounts, data) + if err != nil { + return nil, err + } + return inst, nil +} + +func DecodeInstruction(accounts []*ag_solanago.AccountMeta, data []byte) (*Instruction, error) { + inst := new(Instruction) + if err := ag_binary.NewBorshDecoder(data).Decode(inst); err != nil { + return nil, fmt.Errorf("unable to decode instruction: %w", err) + } + if v, ok := inst.Impl.(ag_solanago.AccountsSettable); ok { + err := v.SetAccounts(accounts) + if err != nil { + return nil, fmt.Errorf("unable to set accounts for instruction: %w", err) + } + } + return inst, nil +} diff --git a/contracts/generated/log_read_test/testing_utils.go b/contracts/generated/log_read_test/testing_utils.go new file mode 100644 index 000000000..963931602 --- /dev/null +++ b/contracts/generated/log_read_test/testing_utils.go @@ -0,0 +1,20 @@ +// Code generated by https://github.com/gagliardetto/anchor-go. DO NOT EDIT. + +package log_read_test + +import ( + "bytes" + "fmt" + ag_binary "github.com/gagliardetto/binary" +) + +func encodeT(data interface{}, buf *bytes.Buffer) error { + if err := ag_binary.NewBorshEncoder(buf).Encode(data); err != nil { + return fmt.Errorf("unable to encode instruction: %w", err) + } + return nil +} + +func decodeT(dst interface{}, data []byte) error { + return ag_binary.NewBorshDecoder(data).Decode(dst) +} diff --git a/contracts/generated/log_read_test/types.go b/contracts/generated/log_read_test/types.go new file mode 100644 index 000000000..981b967ad --- /dev/null +++ b/contracts/generated/log_read_test/types.go @@ -0,0 +1,3 @@ +// Code generated by https://github.com/gagliardetto/anchor-go. DO NOT EDIT. + +package log_read_test diff --git a/contracts/programs/log-read-test/Cargo.toml b/contracts/programs/log-read-test/Cargo.toml new file mode 100644 index 000000000..611d8884c --- /dev/null +++ b/contracts/programs/log-read-test/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "log-read-test" +version = "0.1.0" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "log_read_test" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +anchor-lang = "0.29.0" diff --git a/contracts/programs/log-read-test/Xargo.toml b/contracts/programs/log-read-test/Xargo.toml new file mode 100644 index 000000000..475fb71ed --- /dev/null +++ b/contracts/programs/log-read-test/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/contracts/programs/log-read-test/src/event.rs b/contracts/programs/log-read-test/src/event.rs new file mode 100644 index 000000000..fe49922f4 --- /dev/null +++ b/contracts/programs/log-read-test/src/event.rs @@ -0,0 +1,7 @@ +use anchor_lang::prelude::*; + +#[event] +pub struct TestEvent { + pub str_val: String, + pub u64_value: u64, +} \ No newline at end of file diff --git a/contracts/programs/log-read-test/src/lib.rs b/contracts/programs/log-read-test/src/lib.rs new file mode 100644 index 000000000..295f910cf --- /dev/null +++ b/contracts/programs/log-read-test/src/lib.rs @@ -0,0 +1,25 @@ +use anchor_lang::prelude::*; + +declare_id!("J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4"); + +pub mod event; + +#[program] +pub mod log_read_test { + use super::*; + + pub fn create_log(_ctx: Context, value: u64) -> Result<()> { + emit!(event::TestEvent { + str_val: "Hello, World!".to_string(), + u64_value: value, + }); + + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialization<'info> { + pub authority: Signer<'info>, + pub system_program: Program<'info, System>, +} \ No newline at end of file diff --git a/go.mod b/go.mod index 85c6898ee..eb5ebee6b 100644 --- a/go.mod +++ b/go.mod @@ -52,6 +52,8 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/gorilla/rpc v1.2.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect diff --git a/go.sum b/go.sum index e73004db8..ee75f2544 100644 --- a/go.sum +++ b/go.sum @@ -225,7 +225,9 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= diff --git a/integration-tests/smoke/event_loader_test.go b/integration-tests/smoke/event_loader_test.go new file mode 100644 index 000000000..689610303 --- /dev/null +++ b/integration-tests/smoke/event_loader_test.go @@ -0,0 +1,300 @@ +package smoke + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/base64" + "fmt" + "os" + "path/filepath" + "sync" + "testing" + "time" + + bin "github.com/gagliardetto/binary" + "github.com/gagliardetto/solana-go" + "github.com/gagliardetto/solana-go/rpc" + "github.com/gagliardetto/solana-go/rpc/ws" + "github.com/gagliardetto/solana-go/text" + "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + + contract "github.com/smartcontractkit/chainlink-solana/contracts/generated/log_read_test" + "github.com/smartcontractkit/chainlink-solana/pkg/solana/client" + "github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller" + + "github.com/smartcontractkit/chainlink-solana/integration-tests/solclient" + "github.com/smartcontractkit/chainlink-solana/integration-tests/utils" +) + +type testConfig struct { + PrivateKey string + PublicKey string +} + +const programPubKey = "J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4" + +func TestEventLoader(t *testing.T) { + t.Parallel() + + deadline, ok := t.Deadline() + if !ok { + deadline = time.Now().Add(time.Minute) + } + + ctx, cancel := context.WithDeadline(context.Background(), deadline) + defer cancel() + + // Getting the default localnet private key + privateKey, err := solana.PrivateKeyFromBase58(solclient.DefaultPrivateKeysSolValidator[1]) + require.NoError(t, err) + + rpcURL, wsURL := setupTestValidator(t, privateKey.PublicKey().String()) + rpcClient := rpc.New(rpcURL) + wsClient, err := ws.Connect(ctx, wsURL) + + defer wsClient.Close() + + require.NoError(t, err) + client.FundTestAccounts(t, []solana.PublicKey{privateKey.PublicKey()}, rpcURL) + + totalLogsToSend := 30 + parser := &printParser{t: t} + sender := newLogSender(t, rpcClient, wsClient) + collector := logpoller.NewEncodedLogCollector( + rpcClient, + parser, + logger.Nop(), + ) + + require.NoError(t, collector.Start(ctx)) + t.Cleanup(func() { + require.NoError(t, collector.Close()) + }) + + go func(ctx context.Context, sender *logSender, privateKey *solana.PrivateKey) { + var idx int + + for { + idx++ + if idx > totalLogsToSend { + return + } + + timer := time.NewTimer(time.Second) + + select { + case <-ctx.Done(): + timer.Stop() + + return + case <-timer.C: + if err := sender.sendLog(ctx, func(_ solana.PublicKey) *solana.PrivateKey { + return privateKey + }, privateKey.PublicKey(), uint64(idx)); err != nil { + t.Logf("failed to send log: %s", err) + } + } + + timer.Stop() + } + }(ctx, sender, &privateKey) + + expectedSumOfLogValues := uint64((totalLogsToSend / 2) * (totalLogsToSend + 1)) + + // eventually process all logs + tests.AssertEventually(t, func() bool { + return parser.Sum() == expectedSumOfLogValues + }) +} + +// upgradeAuthority is admin solana.PrivateKey as string +func setupTestValidator(t *testing.T, upgradeAuthority string) (string, string) { + t.Helper() + + soPath := filepath.Join(utils.ContractsDir, "log_read_test.so") + + _, err := os.Stat(soPath) + if err != nil { + t.Log(err.Error()) + t.FailNow() + } + + flags := []string{ + "--warp-slot", "42", + "--upgradeable-program", + programPubKey, + soPath, + upgradeAuthority, + } + + return client.SetupLocalSolNodeWithFlags(t, flags...) +} + +type testEvent struct { + StrVal string + U64Value uint64 +} + +type printParser struct { + t *testing.T + + mu sync.RWMutex + values []uint64 +} + +func (p *printParser) ProcessEvent(evt logpoller.ProgramEvent) error { + p.t.Helper() + + data, err := base64.StdEncoding.DecodeString(evt.Data) + if err != nil { + return err + } + + sum := sha256.Sum256([]byte("event:TestEvent")) + sig := sum[:8] + + if bytes.Equal(sig, data[:8]) { + var event testEvent + if err := bin.UnmarshalBorsh(&event, data[8:]); err != nil { + return nil + } + + p.mu.Lock() + p.values = append(p.values, event.U64Value) + p.mu.Unlock() + } + + return nil +} + +func (p *printParser) Sum() uint64 { + p.t.Helper() + + p.mu.RLock() + defer p.mu.RUnlock() + + var sum uint64 + + for _, value := range p.values { + sum += value + } + + return sum +} + +type logSender struct { + t *testing.T + client *rpc.Client + wsClient *ws.Client + txErrGroup errgroup.Group +} + +func newLogSender(t *testing.T, client *rpc.Client, wsClient *ws.Client) *logSender { + return &logSender{ + t: t, + client: client, + wsClient: wsClient, + txErrGroup: errgroup.Group{}, + } +} + +func (s *logSender) sendLog( + ctx context.Context, + signerFunc func(key solana.PublicKey) *solana.PrivateKey, + payer solana.PublicKey, + value uint64, +) error { + s.t.Helper() + + pubKey, err := solana.PublicKeyFromBase58(programPubKey) + require.NoError(s.t, err) + contract.SetProgramID(pubKey) + + inst, err := contract.NewCreateLogInstruction(value, payer, solana.SystemProgramID).ValidateAndBuild() + if err != nil { + return err + } + + return s.sendInstruction(ctx, inst, signerFunc, payer) +} + +func (s *logSender) sendInstruction( + ctx context.Context, + inst *contract.Instruction, + signerFunc func(key solana.PublicKey) *solana.PrivateKey, + payer solana.PublicKey, +) error { + s.t.Helper() + + recent, err := s.client.GetRecentBlockhash(ctx, rpc.CommitmentFinalized) + if err != nil { + return err + } + + tx, err := solana.NewTransaction( + []solana.Instruction{ + inst, + }, + recent.Value.Blockhash, + solana.TransactionPayer(payer), + ) + if err != nil { + return err + } + + if _, err = tx.EncodeTree(text.NewTreeEncoder(os.Stdout, "Send test log")); err != nil { + return err + } + + if _, err = tx.Sign(signerFunc); err != nil { + return err + } + + sig, err := s.client.SendTransactionWithOpts( + context.Background(), + tx, + rpc.TransactionOpts{ + PreflightCommitment: rpc.CommitmentConfirmed, + }, + ) + + if err != nil { + return err + } + + s.queueTX(sig, rpc.CommitmentConfirmed) + + return nil +} + +func (s *logSender) queueTX(sig solana.Signature, commitment rpc.CommitmentType) { + s.t.Helper() + + s.txErrGroup.Go(func() error { + sub, err := s.wsClient.SignatureSubscribe( + sig, + commitment, + ) + if err != nil { + return err + } + + defer sub.Unsubscribe() + + res, err := sub.Recv() + if err != nil { + return err + } + + if res.Value.Err != nil { + return fmt.Errorf("transaction confirmation failed: %v", res.Value.Err) + } + + return nil + }) +} diff --git a/pkg/solana/client/test_helpers.go b/pkg/solana/client/test_helpers.go index 1e766c02a..02d03183f 100644 --- a/pkg/solana/client/test_helpers.go +++ b/pkg/solana/client/test_helpers.go @@ -3,6 +3,7 @@ package client import ( "bytes" "os/exec" + "strconv" "testing" "time" @@ -15,17 +16,34 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" ) -// SetupLocalSolNode sets up a local solana node via solana cli, and returns the url func SetupLocalSolNode(t *testing.T) string { + t.Helper() + + url, _ := SetupLocalSolNodeWithFlags(t) + + return url +} + +// SetupLocalSolNode sets up a local solana node via solana cli, and returns the url +func SetupLocalSolNodeWithFlags(t *testing.T, flags ...string) (string, string) { + t.Helper() + port := utils.MustRandomPort(t) + portInt, _ := strconv.Atoi(port) + faucetPort := utils.MustRandomPort(t) url := "http://127.0.0.1:" + port - cmd := exec.Command("solana-test-validator", + wsUrl := "ws://127.0.0.1:" + strconv.Itoa(portInt+1) + + args := append([]string{ "--reset", "--rpc-port", port, "--faucet-port", faucetPort, "--ledger", t.TempDir(), - ) + }, flags...) + + cmd := exec.Command("solana-test-validator", args...) + var stdErr bytes.Buffer cmd.Stderr = &stdErr var stdOut bytes.Buffer @@ -57,10 +75,13 @@ func SetupLocalSolNode(t *testing.T) string { t.Logf("Cmd output: %s\nCmd error: %s\n", stdOut.String(), stdErr.String()) } require.True(t, ready) - return url + + return url, wsUrl } func FundTestAccounts(t *testing.T, keys []solana.PublicKey, url string) { + t.Helper() + for i := range keys { account := keys[i].String() _, err := exec.Command("solana", "airdrop", "100", diff --git a/pkg/solana/logpoller/job.go b/pkg/solana/logpoller/job.go new file mode 100644 index 000000000..0d47d1084 --- /dev/null +++ b/pkg/solana/logpoller/job.go @@ -0,0 +1,142 @@ +package logpoller + +import ( + "context" + "fmt" + "time" + + "github.com/gagliardetto/solana-go" + "github.com/gagliardetto/solana-go/rpc" +) + +// Job is a function that should be run by the worker group. The context provided +// allows the Job to cancel if the worker group is closed. All other life-cycle +// management should be wrapped within the Job. +type Job interface { + String() string + Run(context.Context) error +} + +type retryableJob struct { + name string + count uint8 + when time.Time + job Job +} + +func (j retryableJob) String() string { + return j.job.String() +} + +func (j retryableJob) Run(ctx context.Context) error { + return j.job.Run(ctx) +} + +type eventDetail struct { + blockNumber uint64 + blockHash solana.Hash + trxIdx int + trxSig solana.Signature +} + +// processEventJob is a job that processes a single event. The parser should be a pure function +// such that no network requests are made and no side effects are produced. +type processEventJob struct { + parser Parser + event ProgramEvent +} + +func (j *processEventJob) String() string { + return fmt.Sprintf("processEventJob for event: %s", j.event.FunctionName) +} + +func (j *processEventJob) Run(_ context.Context) error { + return j.parser.ProcessEvent(j.event) +} + +// getTransactionsFromBlockJob is a job that fetches transaction signatures from a block and loads +// the job queue with getTransactionLogsJobs for each transaction found in the block. +type getTransactionsFromBlockJob struct { + slotNumber uint64 + client RPCClient + parser Parser + chJobs chan Job +} + +func (j *getTransactionsFromBlockJob) String() string { + return fmt.Sprintf("getTransactionsFromBlockJob for block: %d", j.slotNumber) +} + +func (j *getTransactionsFromBlockJob) Run(ctx context.Context) error { + var excludeRewards bool + + block, err := j.client.GetBlockWithOpts( + ctx, + j.slotNumber, + // You can specify more options here: + &rpc.GetBlockOpts{ + Encoding: solana.EncodingBase64, + Commitment: rpc.CommitmentFinalized, + // get the full transaction details + TransactionDetails: rpc.TransactionDetailsFull, + // exclude rewards + Rewards: &excludeRewards, + }, + ) + if err != nil { + return err + } + + blockSigsOnly, err := j.client.GetBlockWithOpts( + ctx, + j.slotNumber, + // You can specify more options here: + &rpc.GetBlockOpts{ + Encoding: solana.EncodingBase64, + Commitment: rpc.CommitmentFinalized, + // get the signatures only + TransactionDetails: rpc.TransactionDetailsSignatures, + // exclude rewards + Rewards: &excludeRewards, + }, + ) + if err != nil { + return err + } + + detail := eventDetail{ + blockNumber: *block.BlockHeight, + blockHash: block.Blockhash, + } + + for idx, trx := range block.Transactions { + detail.trxIdx = idx + if len(blockSigsOnly.Signatures)-1 <= idx { + detail.trxSig = blockSigsOnly.Signatures[idx] + } + + messagesToEvents(trx.Meta.LogMessages, j.parser, detail, j.chJobs) + } + + return nil +} + +func messagesToEvents(messages []string, parser Parser, detail eventDetail, chJobs chan Job) { + var logIdx uint + for _, outputs := range parse(messages) { + for _, event := range outputs.Events { + logIdx++ + + event.BlockNumber = detail.blockNumber + event.BlockHash = detail.blockHash.String() + event.TransactionHash = detail.trxSig.String() + event.TransactionIndex = detail.trxIdx + event.TransactionLogIndex = logIdx + + chJobs <- &processEventJob{ + parser: parser, + event: event, + } + } + } +} diff --git a/pkg/solana/logpoller/loader.go b/pkg/solana/logpoller/loader.go new file mode 100644 index 000000000..1fb2ff469 --- /dev/null +++ b/pkg/solana/logpoller/loader.go @@ -0,0 +1,265 @@ +package logpoller + +import ( + "context" + "errors" + "sync" + "sync/atomic" + "time" + + "github.com/gagliardetto/solana-go" + "github.com/gagliardetto/solana-go/rpc" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services" +) + +type Parser interface { + // ProcessEvent should take a ProgramEvent and parse it based on log signature + // and expected encoding. Only return errors that cannot be handled and + // should exit further transaction processing on the running thread. + // + // ProcessEvent should be thread safe. + ProcessEvent(ProgramEvent) error +} + +type RPCClient interface { + GetLatestBlockhash(ctx context.Context, commitment rpc.CommitmentType) (out *rpc.GetLatestBlockhashResult, err error) + GetBlocks(ctx context.Context, startSlot uint64, endSlot *uint64, commitment rpc.CommitmentType) (out rpc.BlocksResult, err error) + GetBlockWithOpts(context.Context, uint64, *rpc.GetBlockOpts) (*rpc.GetBlockResult, error) + GetSignaturesForAddressWithOpts(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error) + GetTransaction(context.Context, solana.Signature, *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error) +} + +const ( + DefaultNextSlotPollingInterval = 1_000 * time.Millisecond +) + +type EncodedLogCollector struct { + // service state management + services.Service + engine *services.Engine + + // dependencies and configuration + client RPCClient + parser Parser + lggr logger.Logger + rpcTimeLimit time.Duration + + // internal state + chSlot chan uint64 + chBlock chan uint64 + chJobs chan Job + workers *WorkerGroup + + mu sync.RWMutex + loadingBlocks atomic.Bool + highestSlot uint64 + highestSlotLoaded uint64 + lastSentSlot atomic.Uint64 +} + +func NewEncodedLogCollector( + client RPCClient, + parser Parser, + lggr logger.Logger, +) *EncodedLogCollector { + c := &EncodedLogCollector{ + client: client, + parser: parser, + chSlot: make(chan uint64, 1), + chBlock: make(chan uint64, 1), + chJobs: make(chan Job, 1), + lggr: lggr, + rpcTimeLimit: 1 * time.Second, + } + + c.Service, c.engine = services.Config{ + Name: "EncodedLogCollector", + NewSubServices: func(lggr logger.Logger) []services.Service { + c.workers = NewWorkerGroup(DefaultWorkerCount, lggr) + + return []services.Service{c.workers} + }, + Start: c.start, + Close: c.close, + }.NewServiceEngine(lggr) + + return c +} + +func (c *EncodedLogCollector) BackfillForAddress(ctx context.Context, address string, fromSlot uint64) error { + pubKey, err := solana.PublicKeyFromBase58(address) + if err != nil { + return err + } + + sigs, err := c.client.GetSignaturesForAddressWithOpts(ctx, pubKey, &rpc.GetSignaturesForAddressOpts{ + Commitment: rpc.CommitmentFinalized, + MinContextSlot: &fromSlot, + }) + if err != nil { + return err + } + + slots := make(map[uint64]struct{}) + + for _, sig := range sigs { + _, ok := slots[sig.Slot] + if !ok { + if err := c.workers.Do(ctx, &getTransactionsFromBlockJob{ + slotNumber: sig.Slot, + client: c.client, + parser: c.parser, + chJobs: c.chJobs, + }); err != nil { + return err + } + + slots[sig.Slot] = struct{}{} + } + } + + return nil +} + +func (c *EncodedLogCollector) start(ctx context.Context) error { + c.engine.Go(c.runSlotPolling) + c.engine.Go(c.runSlotProcessing) + c.engine.Go(c.runBlockProcessing) + c.engine.Go(c.runJobProcessing) + + return nil +} + +func (c *EncodedLogCollector) close() error { + return nil +} + +func (c *EncodedLogCollector) runSlotPolling(ctx context.Context) { + for { + timer := time.NewTimer(DefaultNextSlotPollingInterval) + + select { + case <-ctx.Done(): + return + case <-timer.C: + ctxB, cancel := context.WithTimeout(ctx, c.rpcTimeLimit) + + // not to be run as a job, but as a blocking call + result, err := c.client.GetLatestBlockhash(ctxB, rpc.CommitmentFinalized) + if err != nil { + c.lggr.Info("failed to get latest blockhash", "err", err) + cancel() + + continue + } + + cancel() + + // if the slot is not higher than the highest slot, skip it + if c.lastSentSlot.Load() >= result.Context.Slot { + continue + } + + c.lastSentSlot.Store(result.Context.Slot) + c.chSlot <- result.Context.Slot + } + + timer.Stop() + } +} + +func (c *EncodedLogCollector) runSlotProcessing(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + case slot := <-c.chSlot: + c.mu.Lock() + + if slot > c.highestSlot { + c.highestSlot = slot + + if !c.loadingBlocks.Load() { + c.loadingBlocks.Store(true) + + // run routine to load blocks in slot range + go func(start, end uint64) { + defer c.loadingBlocks.Store(false) + + if err := c.loadSlotBlocksRange(ctx, start, end); err != nil { + // TODO: probably log something here + // a retry will happen anyway on the next round of slots + // so the error is handled by doing nothing + c.lggr.Info("failed to load slot blocks range", "start", start, "end", end, "err", err) + + return + } + + c.mu.Lock() + c.highestSlotLoaded = end + c.mu.Unlock() + }(c.highestSlotLoaded+1, c.highestSlot) + } + } + + c.mu.Unlock() + } + } +} + +func (c *EncodedLogCollector) runBlockProcessing(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + case block := <-c.chBlock: + if err := c.workers.Do(ctx, &getTransactionsFromBlockJob{ + slotNumber: block, + client: c.client, + parser: c.parser, + chJobs: c.chJobs, + }); err != nil { + c.lggr.Infof("failed to add job to queue: %s", err) + } + } + } +} + +func (c *EncodedLogCollector) runJobProcessing(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + case job := <-c.chJobs: + if err := c.workers.Do(ctx, job); err != nil { + c.lggr.Infof("failed to add job to queue: %s", err) + } + } + } +} + +func (c *EncodedLogCollector) loadSlotBlocksRange(ctx context.Context, start, end uint64) error { + ctx, cancel := context.WithTimeout(ctx, c.rpcTimeLimit) + defer cancel() + + if start >= end { + return errors.New("the start block must come before the end block") + } + + var ( + result rpc.BlocksResult + err error + ) + + if result, err = c.client.GetBlocks(ctx, start, &end, rpc.CommitmentFinalized); err != nil { + return err + } + + for _, block := range result { + c.chBlock <- block + } + + return nil +} diff --git a/pkg/solana/logpoller/loader_test.go b/pkg/solana/logpoller/loader_test.go new file mode 100644 index 000000000..d6636e3ce --- /dev/null +++ b/pkg/solana/logpoller/loader_test.go @@ -0,0 +1,289 @@ +package logpoller_test + +import ( + "context" + "math/rand/v2" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/gagliardetto/solana-go" + "github.com/gagliardetto/solana-go/rpc" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + + "github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller" + mocks "github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller/mocks" +) + +var ( + messages = []string{ + "Program J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4 invoke [1]", + "Program log: Instruction: CreateLog", + "Program data: HDQnaQjSWwkNAAAASGVsbG8sIFdvcmxkISoAAAAAAAAA", + "Program J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4 consumed 1477 of 200000 compute units", + "Program J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4 success", + } +) + +func TestEncodedLogCollector_StartClose(t *testing.T) { + client := new(mocks.RPCClient) + parser := new(mocks.Parser) + ctx := tests.Context(t) + + collector := logpoller.NewEncodedLogCollector(client, parser, logger.Nop()) + + assert.NoError(t, collector.Start(ctx)) + assert.NoError(t, collector.Close()) +} + +func TestEncodedLogCollector_ParseSingleEvent(t *testing.T) { + client := new(mocks.RPCClient) + parser := new(testParser) + ctx := tests.Context(t) + + collector := logpoller.NewEncodedLogCollector(client, parser, logger.Nop()) + + require.NoError(t, collector.Start(ctx)) + t.Cleanup(func() { + require.NoError(t, collector.Close()) + }) + + slot := uint64(42) + sig := solana.Signature{2, 1, 4, 2} + blockHeight := uint64(21) + + client.EXPECT().GetLatestBlockhash(mock.Anything, rpc.CommitmentFinalized).Return(&rpc.GetLatestBlockhashResult{ + RPCContext: rpc.RPCContext{ + Context: rpc.Context{ + Slot: slot, + }, + }, + }, nil) + + client.EXPECT().GetBlocks(mock.Anything, uint64(1), mock.MatchedBy(func(val *uint64) bool { + return val != nil && *val == slot + }), mock.Anything).Return(rpc.BlocksResult{slot}, nil) + + client.EXPECT().GetBlockWithOpts(mock.Anything, slot, mock.Anything).Return(&rpc.GetBlockResult{ + Transactions: []rpc.TransactionWithMeta{ + { + Meta: &rpc.TransactionMeta{ + LogMessages: messages, + }, + }, + }, + Signatures: []solana.Signature{sig}, + BlockHeight: &blockHeight, + }, nil).Twice() + + tests.AssertEventually(t, func() bool { + return parser.Called() + }) + + client.AssertExpectations(t) +} + +func BenchmarkEncodedLogCollector(b *testing.B) { + ctx := tests.Context(b) + + ticker := time.NewTimer(500 * time.Millisecond) + defer ticker.Stop() + + parser := new(testParser) + blockProducer := &testBlockProducer{ + b: b, + nextSlot: 10, + blockSigs: make(map[uint64][]solana.Signature), + sigs: make(map[string]bool), + } + + collector := logpoller.NewEncodedLogCollector(blockProducer, parser, logger.Nop()) + + require.NoError(b, collector.Start(ctx)) + b.Cleanup(func() { + require.NoError(b, collector.Close()) + }) + + b.ReportAllocs() + b.ResetTimer() + +BenchLoop: + for i := 0; i < b.N; i++ { + select { + case <-ticker.C: + blockProducer.incrementSlot() + case <-ctx.Done(): + continue BenchLoop + default: + blockProducer.makeEvent() + } + } + + b.ReportMetric(float64(parser.Count())/b.Elapsed().Seconds(), "events/sec") + b.ReportMetric(float64(blockProducer.Count())/b.Elapsed().Seconds(), "rcp_calls/sec") +} + +type testBlockProducer struct { + b *testing.B + + mu sync.RWMutex + nextSlot uint64 + blockSigs map[uint64][]solana.Signature + sigs map[string]bool + count uint64 +} + +func (p *testBlockProducer) incrementSlot() { + p.b.Helper() + + p.mu.Lock() + defer p.mu.Unlock() + + p.nextSlot++ + p.blockSigs[p.nextSlot] = make([]solana.Signature, 0, 100) +} + +func (p *testBlockProducer) makeEvent() { + p.b.Helper() + + p.mu.Lock() + defer p.mu.Unlock() + + sig := solana.Signature{byte(rand.Int64())} + + p.blockSigs[p.nextSlot] = append(p.blockSigs[p.nextSlot], sig) + p.sigs[sig.String()] = true +} + +func (p *testBlockProducer) Count() uint64 { + p.mu.RLock() + defer p.mu.RUnlock() + + return p.count +} + +func (p *testBlockProducer) GetLatestBlockhash(_ context.Context, _ rpc.CommitmentType) (out *rpc.GetLatestBlockhashResult, err error) { + p.b.Helper() + + p.mu.Lock() + p.count++ + p.mu.Unlock() + + p.mu.RLock() + defer p.mu.RUnlock() + + return &rpc.GetLatestBlockhashResult{ + RPCContext: rpc.RPCContext{ + Context: rpc.Context{ + Slot: p.nextSlot, + }, + }, + }, nil +} + +func (p *testBlockProducer) GetBlocks(_ context.Context, startSlot uint64, endSlot *uint64, _ rpc.CommitmentType) (out rpc.BlocksResult, err error) { + p.b.Helper() + + p.mu.Lock() + p.count++ + p.mu.Unlock() + + blocks := make([]uint64, *endSlot-startSlot) + for idx := range blocks { + blocks[idx] = startSlot + uint64(idx) + } + + return rpc.BlocksResult(blocks), nil +} + +func (p *testBlockProducer) GetBlockWithOpts(_ context.Context, block uint64, opts *rpc.GetBlockOpts) (*rpc.GetBlockResult, error) { + p.b.Helper() + + p.mu.Lock() + defer p.mu.Unlock() + + var result rpc.GetBlockResult + + sigs := p.blockSigs[block] + + switch opts.TransactionDetails { + case rpc.TransactionDetailsFull: + result.Transactions = make([]rpc.TransactionWithMeta, len(sigs)) + for idx, sig := range sigs { + delete(p.sigs, sig.String()) + + result.Transactions[idx] = rpc.TransactionWithMeta{ + Slot: block, + Meta: &rpc.TransactionMeta{ + LogMessages: messages, + }, + } + } + case rpc.TransactionDetailsSignatures: + result.Signatures = sigs + delete(p.blockSigs, block) + case rpc.TransactionDetailsNone: + fallthrough + default: + } + + p.count++ + result.BlockHeight = &block + + return &result, nil +} + +func (p *testBlockProducer) GetSignaturesForAddressWithOpts(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error) { + p.b.Helper() + + return nil, nil +} + +func (p *testBlockProducer) GetTransaction(_ context.Context, sig solana.Signature, _ *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error) { + p.b.Helper() + + p.mu.Lock() + defer p.mu.Unlock() + + var msgs []string + + p.count++ + _, ok := p.sigs[sig.String()] + if ok { + msgs = messages + } + + delete(p.sigs, sig.String()) + + return &rpc.GetTransactionResult{ + Meta: &rpc.TransactionMeta{ + LogMessages: msgs, + }, + }, nil +} + +type testParser struct { + called atomic.Bool + count atomic.Uint64 +} + +func (p *testParser) ProcessEvent(event logpoller.ProgramEvent) error { + p.called.Store(true) + p.count.Store(p.count.Load() + 1) + + return nil +} + +func (p *testParser) Called() bool { + return p.called.Load() +} + +func (p *testParser) Count() uint64 { + return p.count.Load() +} diff --git a/pkg/solana/logpoller/mocks/parser.go b/pkg/solana/logpoller/mocks/parser.go new file mode 100644 index 000000000..07f0b2e41 --- /dev/null +++ b/pkg/solana/logpoller/mocks/parser.go @@ -0,0 +1,81 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import ( + logpoller "github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller" + mock "github.com/stretchr/testify/mock" +) + +// Parser is an autogenerated mock type for the Parser type +type Parser struct { + mock.Mock +} + +type Parser_Expecter struct { + mock *mock.Mock +} + +func (_m *Parser) EXPECT() *Parser_Expecter { + return &Parser_Expecter{mock: &_m.Mock} +} + +// ProcessEvent provides a mock function with given fields: _a0 +func (_m *Parser) ProcessEvent(_a0 logpoller.ProgramEvent) error { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for ProcessEvent") + } + + var r0 error + if rf, ok := ret.Get(0).(func(logpoller.ProgramEvent) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Parser_ProcessEvent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProcessEvent' +type Parser_ProcessEvent_Call struct { + *mock.Call +} + +// ProcessEvent is a helper method to define mock.On call +// - _a0 logpoller.ProgramEvent +func (_e *Parser_Expecter) ProcessEvent(_a0 interface{}) *Parser_ProcessEvent_Call { + return &Parser_ProcessEvent_Call{Call: _e.mock.On("ProcessEvent", _a0)} +} + +func (_c *Parser_ProcessEvent_Call) Run(run func(_a0 logpoller.ProgramEvent)) *Parser_ProcessEvent_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(logpoller.ProgramEvent)) + }) + return _c +} + +func (_c *Parser_ProcessEvent_Call) Return(_a0 error) *Parser_ProcessEvent_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Parser_ProcessEvent_Call) RunAndReturn(run func(logpoller.ProgramEvent) error) *Parser_ProcessEvent_Call { + _c.Call.Return(run) + return _c +} + +// NewParser creates a new instance of Parser. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewParser(t interface { + mock.TestingT + Cleanup(func()) +}) *Parser { + mock := &Parser{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/solana/logpoller/mocks/rpc_client.go b/pkg/solana/logpoller/mocks/rpc_client.go new file mode 100644 index 000000000..f296e1d26 --- /dev/null +++ b/pkg/solana/logpoller/mocks/rpc_client.go @@ -0,0 +1,340 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + rpc "github.com/gagliardetto/solana-go/rpc" + + solana "github.com/gagliardetto/solana-go" +) + +// RPCClient is an autogenerated mock type for the RPCClient type +type RPCClient struct { + mock.Mock +} + +type RPCClient_Expecter struct { + mock *mock.Mock +} + +func (_m *RPCClient) EXPECT() *RPCClient_Expecter { + return &RPCClient_Expecter{mock: &_m.Mock} +} + +// GetBlockWithOpts provides a mock function with given fields: _a0, _a1, _a2 +func (_m *RPCClient) GetBlockWithOpts(_a0 context.Context, _a1 uint64, _a2 *rpc.GetBlockOpts) (*rpc.GetBlockResult, error) { + ret := _m.Called(_a0, _a1, _a2) + + if len(ret) == 0 { + panic("no return value specified for GetBlockWithOpts") + } + + var r0 *rpc.GetBlockResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, *rpc.GetBlockOpts) (*rpc.GetBlockResult, error)); ok { + return rf(_a0, _a1, _a2) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, *rpc.GetBlockOpts) *rpc.GetBlockResult); ok { + r0 = rf(_a0, _a1, _a2) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetBlockResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, *rpc.GetBlockOpts) error); ok { + r1 = rf(_a0, _a1, _a2) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RPCClient_GetBlockWithOpts_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlockWithOpts' +type RPCClient_GetBlockWithOpts_Call struct { + *mock.Call +} + +// GetBlockWithOpts is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 uint64 +// - _a2 *rpc.GetBlockOpts +func (_e *RPCClient_Expecter) GetBlockWithOpts(_a0 interface{}, _a1 interface{}, _a2 interface{}) *RPCClient_GetBlockWithOpts_Call { + return &RPCClient_GetBlockWithOpts_Call{Call: _e.mock.On("GetBlockWithOpts", _a0, _a1, _a2)} +} + +func (_c *RPCClient_GetBlockWithOpts_Call) Run(run func(_a0 context.Context, _a1 uint64, _a2 *rpc.GetBlockOpts)) *RPCClient_GetBlockWithOpts_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(*rpc.GetBlockOpts)) + }) + return _c +} + +func (_c *RPCClient_GetBlockWithOpts_Call) Return(_a0 *rpc.GetBlockResult, _a1 error) *RPCClient_GetBlockWithOpts_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *RPCClient_GetBlockWithOpts_Call) RunAndReturn(run func(context.Context, uint64, *rpc.GetBlockOpts) (*rpc.GetBlockResult, error)) *RPCClient_GetBlockWithOpts_Call { + _c.Call.Return(run) + return _c +} + +// GetBlocks provides a mock function with given fields: ctx, startSlot, endSlot, commitment +func (_m *RPCClient) GetBlocks(ctx context.Context, startSlot uint64, endSlot *uint64, commitment rpc.CommitmentType) (rpc.BlocksResult, error) { + ret := _m.Called(ctx, startSlot, endSlot, commitment) + + if len(ret) == 0 { + panic("no return value specified for GetBlocks") + } + + var r0 rpc.BlocksResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, *uint64, rpc.CommitmentType) (rpc.BlocksResult, error)); ok { + return rf(ctx, startSlot, endSlot, commitment) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, *uint64, rpc.CommitmentType) rpc.BlocksResult); ok { + r0 = rf(ctx, startSlot, endSlot, commitment) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(rpc.BlocksResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, *uint64, rpc.CommitmentType) error); ok { + r1 = rf(ctx, startSlot, endSlot, commitment) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RPCClient_GetBlocks_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlocks' +type RPCClient_GetBlocks_Call struct { + *mock.Call +} + +// GetBlocks is a helper method to define mock.On call +// - ctx context.Context +// - startSlot uint64 +// - endSlot *uint64 +// - commitment rpc.CommitmentType +func (_e *RPCClient_Expecter) GetBlocks(ctx interface{}, startSlot interface{}, endSlot interface{}, commitment interface{}) *RPCClient_GetBlocks_Call { + return &RPCClient_GetBlocks_Call{Call: _e.mock.On("GetBlocks", ctx, startSlot, endSlot, commitment)} +} + +func (_c *RPCClient_GetBlocks_Call) Run(run func(ctx context.Context, startSlot uint64, endSlot *uint64, commitment rpc.CommitmentType)) *RPCClient_GetBlocks_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(*uint64), args[3].(rpc.CommitmentType)) + }) + return _c +} + +func (_c *RPCClient_GetBlocks_Call) Return(out rpc.BlocksResult, err error) *RPCClient_GetBlocks_Call { + _c.Call.Return(out, err) + return _c +} + +func (_c *RPCClient_GetBlocks_Call) RunAndReturn(run func(context.Context, uint64, *uint64, rpc.CommitmentType) (rpc.BlocksResult, error)) *RPCClient_GetBlocks_Call { + _c.Call.Return(run) + return _c +} + +// GetLatestBlockhash provides a mock function with given fields: ctx, commitment +func (_m *RPCClient) GetLatestBlockhash(ctx context.Context, commitment rpc.CommitmentType) (*rpc.GetLatestBlockhashResult, error) { + ret := _m.Called(ctx, commitment) + + if len(ret) == 0 { + panic("no return value specified for GetLatestBlockhash") + } + + var r0 *rpc.GetLatestBlockhashResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, rpc.CommitmentType) (*rpc.GetLatestBlockhashResult, error)); ok { + return rf(ctx, commitment) + } + if rf, ok := ret.Get(0).(func(context.Context, rpc.CommitmentType) *rpc.GetLatestBlockhashResult); ok { + r0 = rf(ctx, commitment) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetLatestBlockhashResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, rpc.CommitmentType) error); ok { + r1 = rf(ctx, commitment) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RPCClient_GetLatestBlockhash_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestBlockhash' +type RPCClient_GetLatestBlockhash_Call struct { + *mock.Call +} + +// GetLatestBlockhash is a helper method to define mock.On call +// - ctx context.Context +// - commitment rpc.CommitmentType +func (_e *RPCClient_Expecter) GetLatestBlockhash(ctx interface{}, commitment interface{}) *RPCClient_GetLatestBlockhash_Call { + return &RPCClient_GetLatestBlockhash_Call{Call: _e.mock.On("GetLatestBlockhash", ctx, commitment)} +} + +func (_c *RPCClient_GetLatestBlockhash_Call) Run(run func(ctx context.Context, commitment rpc.CommitmentType)) *RPCClient_GetLatestBlockhash_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(rpc.CommitmentType)) + }) + return _c +} + +func (_c *RPCClient_GetLatestBlockhash_Call) Return(out *rpc.GetLatestBlockhashResult, err error) *RPCClient_GetLatestBlockhash_Call { + _c.Call.Return(out, err) + return _c +} + +func (_c *RPCClient_GetLatestBlockhash_Call) RunAndReturn(run func(context.Context, rpc.CommitmentType) (*rpc.GetLatestBlockhashResult, error)) *RPCClient_GetLatestBlockhash_Call { + _c.Call.Return(run) + return _c +} + +// GetSignaturesForAddressWithOpts provides a mock function with given fields: _a0, _a1, _a2 +func (_m *RPCClient) GetSignaturesForAddressWithOpts(_a0 context.Context, _a1 solana.PublicKey, _a2 *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error) { + ret := _m.Called(_a0, _a1, _a2) + + if len(ret) == 0 { + panic("no return value specified for GetSignaturesForAddressWithOpts") + } + + var r0 []*rpc.TransactionSignature + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error)); ok { + return rf(_a0, _a1, _a2) + } + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) []*rpc.TransactionSignature); ok { + r0 = rf(_a0, _a1, _a2) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*rpc.TransactionSignature) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) error); ok { + r1 = rf(_a0, _a1, _a2) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RPCClient_GetSignaturesForAddressWithOpts_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSignaturesForAddressWithOpts' +type RPCClient_GetSignaturesForAddressWithOpts_Call struct { + *mock.Call +} + +// GetSignaturesForAddressWithOpts is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 solana.PublicKey +// - _a2 *rpc.GetSignaturesForAddressOpts +func (_e *RPCClient_Expecter) GetSignaturesForAddressWithOpts(_a0 interface{}, _a1 interface{}, _a2 interface{}) *RPCClient_GetSignaturesForAddressWithOpts_Call { + return &RPCClient_GetSignaturesForAddressWithOpts_Call{Call: _e.mock.On("GetSignaturesForAddressWithOpts", _a0, _a1, _a2)} +} + +func (_c *RPCClient_GetSignaturesForAddressWithOpts_Call) Run(run func(_a0 context.Context, _a1 solana.PublicKey, _a2 *rpc.GetSignaturesForAddressOpts)) *RPCClient_GetSignaturesForAddressWithOpts_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(solana.PublicKey), args[2].(*rpc.GetSignaturesForAddressOpts)) + }) + return _c +} + +func (_c *RPCClient_GetSignaturesForAddressWithOpts_Call) Return(_a0 []*rpc.TransactionSignature, _a1 error) *RPCClient_GetSignaturesForAddressWithOpts_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *RPCClient_GetSignaturesForAddressWithOpts_Call) RunAndReturn(run func(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error)) *RPCClient_GetSignaturesForAddressWithOpts_Call { + _c.Call.Return(run) + return _c +} + +// GetTransaction provides a mock function with given fields: _a0, _a1, _a2 +func (_m *RPCClient) GetTransaction(_a0 context.Context, _a1 solana.Signature, _a2 *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error) { + ret := _m.Called(_a0, _a1, _a2) + + if len(ret) == 0 { + panic("no return value specified for GetTransaction") + } + + var r0 *rpc.GetTransactionResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error)); ok { + return rf(_a0, _a1, _a2) + } + if rf, ok := ret.Get(0).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) *rpc.GetTransactionResult); ok { + r0 = rf(_a0, _a1, _a2) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetTransactionResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) error); ok { + r1 = rf(_a0, _a1, _a2) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RPCClient_GetTransaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTransaction' +type RPCClient_GetTransaction_Call struct { + *mock.Call +} + +// GetTransaction is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 solana.Signature +// - _a2 *rpc.GetTransactionOpts +func (_e *RPCClient_Expecter) GetTransaction(_a0 interface{}, _a1 interface{}, _a2 interface{}) *RPCClient_GetTransaction_Call { + return &RPCClient_GetTransaction_Call{Call: _e.mock.On("GetTransaction", _a0, _a1, _a2)} +} + +func (_c *RPCClient_GetTransaction_Call) Run(run func(_a0 context.Context, _a1 solana.Signature, _a2 *rpc.GetTransactionOpts)) *RPCClient_GetTransaction_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(solana.Signature), args[2].(*rpc.GetTransactionOpts)) + }) + return _c +} + +func (_c *RPCClient_GetTransaction_Call) Return(_a0 *rpc.GetTransactionResult, _a1 error) *RPCClient_GetTransaction_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *RPCClient_GetTransaction_Call) RunAndReturn(run func(context.Context, solana.Signature, *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error)) *RPCClient_GetTransaction_Call { + _c.Call.Return(run) + return _c +} + +// NewRPCClient creates a new instance of RPCClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewRPCClient(t interface { + mock.TestingT + Cleanup(func()) +}) *RPCClient { + mock := &RPCClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/solana/logpoller/parser.go b/pkg/solana/logpoller/parser.go new file mode 100644 index 000000000..3367ba3a3 --- /dev/null +++ b/pkg/solana/logpoller/parser.go @@ -0,0 +1,194 @@ +package logpoller + +import ( + "fmt" + "regexp" + "strconv" + "strings" +) + +type MessageStyle string + +const ( + MessageStyleMuted MessageStyle = "muted" + MessageStyleInfo MessageStyle = "info" + MessageStyleSuccess MessageStyle = "success" + MessageStyleWarning MessageStyle = "warning" +) + +var ( + invokeMatcher = regexp.MustCompile(`Program (\w*) invoke \[(\d)\]`) + consumedMatcher = regexp.MustCompile(`Program \w* consumed (\d*) (.*)`) + logMatcher = regexp.MustCompile(`Program log: (.*)`) + dataMatcher = regexp.MustCompile(`Program data: (.*)`) + instructionMatcher = regexp.MustCompile(`Instruction: (.*)`) +) + +type BlockData struct { + BlockNumber uint64 + BlockHash string + TransactionHash string + TransactionIndex int + TransactionLogIndex uint +} + +type ProgramLog struct { + BlockData + Text string + Prefix string + Style MessageStyle +} + +type ProgramEvent struct { + BlockData + Prefix string + FunctionName string + Data string +} + +type ProgramOutput struct { + Program string + Logs []ProgramLog + Events []ProgramEvent + ComputeUnits uint + Truncated bool + Failed bool +} + +func prefixBuilder(depth int) string { + return strings.Repeat(">", depth) +} + +/* +Program J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4 invoke [1] +Program log: Instruction: CreateLog +Program data: HDQnaQjSWwkNAAAASGVsbG8sIFdvcmxkISoAAAAAAAAA // base64 encoded; borsh encoded with identifier +Program J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4 consumed 1477 of 200000 compute units +Program J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4 success +*/ +func parse(logs []string) []ProgramOutput { + var depth int + + instLogs := []ProgramOutput{} + lastEventIdx := -1 + + for _, log := range logs { + if strings.HasPrefix(log, "Program log:") { + logDataMatches := logMatcher.FindStringSubmatch(log) + + if len(logDataMatches) <= 1 { + continue + } + + instructionMatches := instructionMatcher.FindStringSubmatch(logDataMatches[1]) + + if len(instructionMatches) > 1 { + // is an event which should be followed by: Program data: (.*) + instLogs[len(instLogs)-1].Events = append(instLogs[len(instLogs)-1].Events, ProgramEvent{ + Prefix: prefixBuilder(depth), + FunctionName: instructionMatches[1], + }) + + lastEventIdx = len(instLogs[len(instLogs)-1].Events) - 1 + } else { + // if contains: Instruction: (.*) this is an event and should be followed by: Program data: + // else this is a log + instLogs[len(instLogs)-1].Logs = append(instLogs[len(instLogs)-1].Logs, ProgramLog{ + Prefix: prefixBuilder(depth), + Style: MessageStyleMuted, + Text: log, + }) + } + } else if strings.HasPrefix(log, "Program data:") { + dataMatches := dataMatcher.FindStringSubmatch(log) + + if len(dataMatches) > 1 { + if lastEventIdx > -1 { + instLogs[len(instLogs)-1].Events[lastEventIdx].Data = dataMatches[1] + } + } + } else if strings.HasPrefix(log, "Log truncated") { + instLogs[len(instLogs)-1].Truncated = true + } else { + matches := invokeMatcher.FindStringSubmatch(log) + + if len(matches) > 0 { + if depth == 0 { + instLogs = append(instLogs, ProgramOutput{ + ComputeUnits: 0, + Failed: false, + Program: matches[1], + Logs: []ProgramLog{}, + Truncated: false, + }) + } else { + instLogs[len(instLogs)-1].Logs = append(instLogs[len(instLogs)-1].Logs, ProgramLog{ + Prefix: prefixBuilder(depth), + Style: MessageStyleInfo, + Text: fmt.Sprintf("Program invoked: %s", matches[1]), + }) + } + + depth++ + } else if strings.Contains(log, "success") { + instLogs[len(instLogs)-1].Logs = append(instLogs[len(instLogs)-1].Logs, ProgramLog{ + Prefix: prefixBuilder(depth), + Style: MessageStyleSuccess, + Text: "Program returned success", + }) + + depth-- + } else if strings.Contains(log, "failed") { + instLogs[len(instLogs)-1].Failed = true + + idx := strings.Index(log, ": ") + 2 + currText := fmt.Sprintf(`Program returned error: "%s"`, log[idx:]) + + // failed to verify log of previous program so reset depth and print full log + if strings.HasPrefix(log, "failed") { + depth++ + + currText = strings.ToTitle(log) + } + + instLogs[len(instLogs)-1].Logs = append(instLogs[len(instLogs)-1].Logs, ProgramLog{ + Prefix: prefixBuilder(depth), + Style: MessageStyleWarning, + Text: currText, + }) + + depth-- + } else { + if depth == 0 { + instLogs = append(instLogs, ProgramOutput{ + ComputeUnits: 0, + Failed: false, + Program: "", + Logs: []ProgramLog{}, + Truncated: false, + }) + } + + matches := consumedMatcher.FindStringSubmatch(log) + if len(matches) == 3 { + if depth == 1 { + if val, err := strconv.Atoi(matches[1]); err == nil { + instLogs[len(instLogs)-1].ComputeUnits = uint(val) + } + } + + log = fmt.Sprintf("Program consumed: %s %s", matches[1], matches[2]) + } + + // native program logs don't start with "Program log:" + instLogs[len(instLogs)-1].Logs = append(instLogs[len(instLogs)-1].Logs, ProgramLog{ + Prefix: prefixBuilder(depth), + Style: MessageStyleMuted, + Text: log, + }) + } + } + } + + return instLogs +} diff --git a/pkg/solana/logpoller/worker.go b/pkg/solana/logpoller/worker.go new file mode 100644 index 000000000..73d1b421e --- /dev/null +++ b/pkg/solana/logpoller/worker.go @@ -0,0 +1,382 @@ +package logpoller + +import ( + "context" + "crypto/rand" + "fmt" + "math/big" + "sync" + "sync/atomic" + "time" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services" +) + +var ( + ErrProcessStopped = fmt.Errorf("worker process has stopped") + ErrContextCancelled = fmt.Errorf("worker context cancelled") +) + +const ( + // DefaultMaxRetryCount is the number of times a job will be retried before being dropped. + DefaultMaxRetryCount = 6 + // DefaultNotifyRetryDepth is the retry queue depth at which the worker group will log a warning. + DefaultNotifyRetryDepth = 200 + // DefaultNotifyQueueDepth is the queue depth at which the worker group will log a warning. + DefaultNotifyQueueDepth = 100 + // DefaultWorkerCount is the default number of workers in a WorkerGroup. + DefaultWorkerCount = 10 +) + +type worker struct { + Name string + Queue chan *worker + Retry chan Job + Lggr logger.Logger +} + +func (w *worker) Do(ctx context.Context, job Job) { + if ctx.Err() == nil { + if err := job.Run(ctx); err != nil { + w.Lggr.Infof("job %s failed with error; retrying: %s", job, err) + w.Retry <- job + } + } + + // put itself back on the queue when done + select { + case w.Queue <- w: + default: + } +} + +type WorkerGroup struct { + // service state management + services.Service + engine *services.Engine + + // dependencies and configuration + maxWorkers int + maxRetryCount uint8 + lggr logger.Logger + + // worker group state + activeWorkers int + workers chan *worker + queue *queue[Job] + input chan Job + chInputNotify chan struct{} + + chStopInputs chan struct{} + queueClosed atomic.Bool + + // retry queue + chRetry chan Job + mu sync.RWMutex + retryMap map[string]retryableJob +} + +func NewWorkerGroup(workers int, lggr logger.Logger) *WorkerGroup { + g := &WorkerGroup{ + maxWorkers: workers, + maxRetryCount: DefaultMaxRetryCount, + workers: make(chan *worker, workers), + lggr: lggr, + queue: newQueue[Job](0), + input: make(chan Job, 1), + chInputNotify: make(chan struct{}, 1), + chStopInputs: make(chan struct{}), + chRetry: make(chan Job, 1), + retryMap: make(map[string]retryableJob), + } + + g.Service, g.engine = services.Config{ + Name: "WorkerGroup", + Start: g.start, + Close: g.close, + }.NewServiceEngine(lggr) + + return g +} + +var _ services.Service = &WorkerGroup{} + +func (g *WorkerGroup) start(ctx context.Context) error { + g.engine.Go(g.runQueuing) + g.engine.Go(g.runProcessing) + g.engine.Go(g.runRetryQueue) + g.engine.Go(g.runRetries) + + return nil +} + +func (g *WorkerGroup) close() error { + if !g.queueClosed.Load() { + g.queueClosed.Store(true) + close(g.chStopInputs) + } + + return nil +} + +// Do adds a new work item onto the work queue. This function blocks until +// the work queue clears up or the context is cancelled. This allows a max wait +// time for the queue to open. Or a context can wrap a collection of jobs that +// need to be run and when the context cancels, the jobs don't get added to the +// queue. +func (g *WorkerGroup) Do(ctx context.Context, job Job) error { + if ctx.Err() != nil { + return fmt.Errorf("%w; work not added to queue", ErrContextCancelled) + } + + if g.queueClosed.Load() { + return fmt.Errorf("%w; work not added to queue", ErrProcessStopped) + } + + select { + case g.input <- job: + return nil + case <-ctx.Done(): + return fmt.Errorf("%w; work not added to queue", ErrContextCancelled) + case <-g.chStopInputs: + return fmt.Errorf("%w; work not added to queue", ErrProcessStopped) + } +} + +func (g *WorkerGroup) runQueuing(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + case item := <-g.input: + g.queue.Add(item) + + // notify that new work item came in + // drop if notification channel is full + select { + case g.chInputNotify <- struct{}{}: + default: + } + } + } +} + +func (g *WorkerGroup) runProcessing(ctx context.Context) { +Loop: + for { + select { + // watch notification channel and begin processing queue + // when notification occurs + case <-g.chInputNotify: + g.processQueue(ctx) + case <-ctx.Done(): + break Loop + } + } + + // run the job queue one more time just in case some + // new work items snuck in + g.processQueue(ctx) +} + +func (g *WorkerGroup) runRetryQueue(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + case job := <-g.chRetry: + var retry retryableJob + + switch job.(type) { + case retryableJob: + retry = job.(retryableJob) + retry.count++ + + if retry.count > g.maxRetryCount { + g.lggr.Infof("job %s dropped after max retries", job) + + continue + } + + wait := calculateExponentialBackoff(retry.count) + g.lggr.Infof("retrying job in %dms", wait/time.Millisecond) + + retry.when = time.Now().Add(wait) + default: + wait := calculateExponentialBackoff(0) + + g.lggr.Infof("retrying job %s in %dms", job, wait/time.Millisecond) + + retry = retryableJob{ + name: createRandomString(12), + job: job, + when: time.Now().Add(wait), + } + } + + g.mu.Lock() + g.retryMap[retry.name] = retry + + if len(g.retryMap) >= DefaultNotifyRetryDepth { + g.lggr.Infof("retry queue depth: %d", len(g.retryMap)) + } + g.mu.Unlock() + } + } +} + +func (g *WorkerGroup) runRetries(ctx context.Context) { + for { + // run timer on minimum backoff + timer := time.NewTimer(calculateExponentialBackoff(0)) + + select { + case <-ctx.Done(): + timer.Stop() + + return + case <-timer.C: + keys := make([]string, 0, len(g.retryMap)) + retries := make([]retryableJob, 0, len(g.retryMap)) + + g.mu.RLock() + for key, retry := range g.retryMap { + if time.Now().After(retry.when) { + keys = append(keys, key) + retries = append(retries, retry) + } + } + g.mu.RUnlock() + + for idx, key := range keys { + g.mu.Lock() + delete(g.retryMap, key) + g.mu.Unlock() + + g.doJob(ctx, retries[idx]) + } + + timer.Stop() + } + } +} + +func (g *WorkerGroup) processQueue(ctx context.Context) { + for { + if g.queue.Len() == 0 { + break + } + + if g.queue.Len() >= DefaultNotifyQueueDepth { + g.lggr.Infof("queue depth: %d", g.queue.Len()) + } + + value, err := g.queue.Pop() + + // an error from pop means there is nothing to pop + // the length check above should protect from that, but just in case + // this error also breaks the loop + if err != nil { + break + } + + g.doJob(ctx, value) + } +} + +func (g *WorkerGroup) doJob(ctx context.Context, job Job) { + var wkr *worker + + // no read or write locks on activeWorkers or maxWorkers because it's + // assumed the job loop is a single process reading from the job queue + if g.activeWorkers < g.maxWorkers { + // create a new worker + wkr = &worker{ + Name: fmt.Sprintf("worker-%d", g.activeWorkers+1), + Queue: g.workers, + Retry: g.chRetry, + Lggr: g.lggr, + } + + g.activeWorkers++ + } else { + // wait for a worker to be available + wkr = <-g.workers + } + + // have worker do the work + go wkr.Do(ctx, job) +} + +type queue[T any] struct { + mu sync.RWMutex + values []T +} + +func newQueue[T any](len uint) *queue[T] { + values := make([]T, len) + + return &queue[T]{ + values: values, + } +} + +func (q *queue[T]) Add(values ...T) { + q.mu.Lock() + defer q.mu.Unlock() + + q.values = append(q.values, values...) +} + +func (q *queue[T]) Pop() (T, error) { + q.mu.Lock() + defer q.mu.Unlock() + + if len(q.values) == 0 { + return getZero[T](), fmt.Errorf("no values to return") + } + + val := q.values[0] + + if len(q.values) > 1 { + q.values = q.values[1:] + } else { + q.values = []T{} + } + + return val, nil +} + +func (q *queue[T]) Len() int { + q.mu.RLock() + defer q.mu.RUnlock() + + return len(q.values) +} + +func getZero[T any]() T { + var result T + return result +} + +func createRandomString(length int) string { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + b := make([]byte, length) + + for i := range b { + rVal, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset)))) + if err != nil { + rVal = big.NewInt(12) + } + + b[i] = charset[rVal.Int64()] + } + + return string(b) +} + +func calculateExponentialBackoff(retries uint8) time.Duration { + // 200ms, 400ms, 800ms, 1.6s, 3.2s, 6.4s + return time.Duration(2< Date: Thu, 31 Oct 2024 08:49:12 -0500 Subject: [PATCH 02/19] mod tidy --- go.mod | 2 -- go.sum | 2 -- 2 files changed, 4 deletions(-) diff --git a/go.mod b/go.mod index eb5ebee6b..85c6898ee 100644 --- a/go.mod +++ b/go.mod @@ -52,8 +52,6 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/gorilla/rpc v1.2.0 // indirect - github.com/gorilla/websocket v1.4.2 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect diff --git a/go.sum b/go.sum index ee75f2544..e73004db8 100644 --- a/go.sum +++ b/go.sum @@ -225,9 +225,7 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= From 4cd04c048853285f6a5df3726cce2897120077de Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Thu, 31 Oct 2024 09:24:49 -0500 Subject: [PATCH 03/19] standardize mocks with mockery config and auto-format contract --- .mockery.yaml | 30 +- contracts/pnpm-lock.yaml | 1991 +++++++++-------- contracts/programs/log-read-test/src/event.rs | 2 +- contracts/programs/log-read-test/src/lib.rs | 4 +- integration-tests/smoke/event_loader_test.go | 6 +- pkg/monitoring/chain_reader.go | 1 - pkg/monitoring/metrics/feedbalances.go | 2 - pkg/monitoring/metrics/fees.go | 2 - pkg/monitoring/metrics/mocks/FeedBalances.go | 69 - pkg/monitoring/metrics/mocks/Fees.go | 66 + pkg/monitoring/metrics/mocks/NetworkFees.go | 37 - pkg/monitoring/metrics/mocks/NodeBalances.go | 34 - pkg/monitoring/metrics/mocks/NodeSuccess.go | 37 - .../metrics/mocks/ReportObservations.go | 37 - pkg/monitoring/metrics/mocks/SlotHeight.go | 37 - pkg/monitoring/metrics/mocks/feed_balances.go | 164 ++ pkg/monitoring/metrics/mocks/network_fees.go | 101 + pkg/monitoring/metrics/mocks/node_balances.go | 101 + pkg/monitoring/metrics/mocks/node_success.go | 102 + .../metrics/mocks/report_observations.go | 102 + pkg/monitoring/metrics/mocks/slot_height.go | 102 + pkg/monitoring/metrics/networkfees.go | 2 - pkg/monitoring/metrics/nodebalances.go | 2 - pkg/monitoring/metrics/nodesuccess.go | 2 - pkg/monitoring/metrics/reportobservations.go | 2 - pkg/monitoring/metrics/slotheight.go | 2 - pkg/monitoring/mocks/ChainReader.go | 282 --- pkg/monitoring/mocks/chain_reader.go | 527 +++++ pkg/solana/client/client.go | 1 - pkg/solana/client/mocks/ReaderWriter.go | 384 ---- pkg/solana/client/mocks/reader_writer.go | 739 ++++++ pkg/solana/client/test_helpers.go | 4 +- pkg/solana/config/config.go | 1 - pkg/solana/config/mocks/config.go | 548 +++++ pkg/solana/fees/estimator.go | 1 - pkg/solana/fees/mocks/Estimator.go | 90 + pkg/solana/logpoller/parser.go | 2 +- pkg/solana/logpoller/worker.go | 4 +- pkg/solana/logpoller/worker_test.go | 11 +- pkg/solana/txm/mocks/simple_keystore.go | 66 + pkg/solana/txm/txm.go | 1 - 41 files changed, 3856 insertions(+), 1842 deletions(-) delete mode 100644 pkg/monitoring/metrics/mocks/FeedBalances.go delete mode 100644 pkg/monitoring/metrics/mocks/NetworkFees.go delete mode 100644 pkg/monitoring/metrics/mocks/NodeBalances.go delete mode 100644 pkg/monitoring/metrics/mocks/NodeSuccess.go delete mode 100644 pkg/monitoring/metrics/mocks/ReportObservations.go delete mode 100644 pkg/monitoring/metrics/mocks/SlotHeight.go create mode 100644 pkg/monitoring/metrics/mocks/feed_balances.go create mode 100644 pkg/monitoring/metrics/mocks/network_fees.go create mode 100644 pkg/monitoring/metrics/mocks/node_balances.go create mode 100644 pkg/monitoring/metrics/mocks/node_success.go create mode 100644 pkg/monitoring/metrics/mocks/report_observations.go create mode 100644 pkg/monitoring/metrics/mocks/slot_height.go delete mode 100644 pkg/monitoring/mocks/ChainReader.go create mode 100644 pkg/monitoring/mocks/chain_reader.go delete mode 100644 pkg/solana/client/mocks/ReaderWriter.go create mode 100644 pkg/solana/client/mocks/reader_writer.go diff --git a/.mockery.yaml b/.mockery.yaml index d9854e095..cc28bbec1 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -3,7 +3,35 @@ mockname: "{{ .InterfaceName }}" outpkg: mocks filename: "{{ .InterfaceName | snakecase }}.go" packages: + github.com/smartcontractkit/chainlink-solana/pkg/monitoring: + interfaces: + ChainReader: + github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics: + interfaces: + FeedBalances: + Fees: + NetworkFees: + NodeBalances: + NodeSuccess: + ReportObservations: + SlotHeight: + github.com/smartcontractkit/chainlink-solana/pkg/solana/client: + interfaces: + ReaderWriter: + github.com/smartcontractkit/chainlink-solana/pkg/solana/config: + interfaces: + Config: + filename: config.go + case: underscore github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller: interfaces: RPCClient: - Parser: \ No newline at end of file + Parser: + github.com/smartcontractkit/chainlink-solana/pkg/solana/fees: + interfaces: + Estimator: + github.com/smartcontractkit/chainlink-solana/pkg/solana/txm: + interfaces: + SimpleKeystore: + filename: simple_keystore.go + case: underscore \ No newline at end of file diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index 86fd48c66..860108de1 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -1,77 +1,899 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - '@chainlink/solana-sdk': - specifier: link:../ts - version: link:../ts - '@coral-xyz/anchor': - specifier: ^0.29.0 - version: 0.29.0 - '@solana/spl-token': - specifier: ^0.3.5 - version: 0.3.11(@solana/web3.js@1.92.3)(fastestsmallesttextencoderdecoder@1.0.22) - '@solana/web3.js': - specifier: ^1.50.1 <=1.92.3 - version: 1.92.3 - '@types/chai': - specifier: ^4.2.22 - version: 4.3.12 - '@types/mocha': - specifier: ^9.0.0 - version: 9.1.1 - '@types/node': - specifier: ^14.14.37 - version: 14.18.63 - '@types/secp256k1': - specifier: ^4.0.3 - version: 4.0.6 - bn.js: - specifier: ^5.2.0 - version: 5.2.1 - borsh: - specifier: ^0.7.0 - version: 0.7.0 - chai: - specifier: ^4.3.4 - version: 4.4.1 - ethereum-cryptography: - specifier: ^0.1.3 - version: 0.1.3 - mocha: - specifier: ^9.0.0 - version: 9.2.2 - prettier: - specifier: ^2.5.1 - version: 2.8.8 - rpc-websockets: - specifier: <=7.10.0 - version: 7.10.0 - secp256k1: - specifier: ^4.0.2 - version: 4.0.3 - ts-mocha: - specifier: ^8.0.0 - version: 8.0.0(mocha@9.2.2) - typescript: - specifier: ^4.5.4 - version: 4.9.5 +importers: + + .: + dependencies: + '@chainlink/solana-sdk': + specifier: link:../ts + version: link:../ts + '@coral-xyz/anchor': + specifier: ^0.29.0 + version: 0.29.0 + '@solana/spl-token': + specifier: ^0.3.5 + version: 0.3.11(@solana/web3.js@1.92.3)(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/web3.js': + specifier: ^1.50.1 <=1.92.3 + version: 1.92.3 + '@types/chai': + specifier: ^4.2.22 + version: 4.3.12 + '@types/mocha': + specifier: ^9.0.0 + version: 9.1.1 + '@types/node': + specifier: ^14.14.37 + version: 14.18.63 + '@types/secp256k1': + specifier: ^4.0.3 + version: 4.0.6 + bn.js: + specifier: ^5.2.0 + version: 5.2.1 + borsh: + specifier: ^0.7.0 + version: 0.7.0 + chai: + specifier: ^4.3.4 + version: 4.4.1 + ethereum-cryptography: + specifier: ^0.1.3 + version: 0.1.3 + mocha: + specifier: ^9.0.0 + version: 9.2.2 + prettier: + specifier: ^2.5.1 + version: 2.8.8 + rpc-websockets: + specifier: <=7.10.0 + version: 7.10.0 + secp256k1: + specifier: ^4.0.2 + version: 4.0.3 + ts-mocha: + specifier: ^8.0.0 + version: 8.0.0(mocha@9.2.2) + typescript: + specifier: ^4.5.4 + version: 4.9.5 packages: - /@babel/runtime@7.25.6: + '@babel/runtime@7.25.6': resolution: {integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==} engines: {node: '>=6.9.0'} + + '@coral-xyz/anchor@0.29.0': + resolution: {integrity: sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA==} + engines: {node: '>=11'} + + '@coral-xyz/borsh@0.29.0': + resolution: {integrity: sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ==} + engines: {node: '>=10'} + peerDependencies: + '@solana/web3.js': ^1.68.0 + + '@noble/curves@1.6.0': + resolution: {integrity: sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.5.0': + resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==} + engines: {node: ^14.21.3 || >=16} + + '@solana/buffer-layout-utils@0.2.0': + resolution: {integrity: sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==} + engines: {node: '>= 10'} + + '@solana/buffer-layout@4.0.1': + resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} + engines: {node: '>=5.10'} + + '@solana/codecs-core@2.0.0-experimental.8618508': + resolution: {integrity: sha512-JCz7mKjVKtfZxkuDtwMAUgA7YvJcA2BwpZaA1NOLcted4OMC4Prwa3DUe3f3181ixPYaRyptbF0Ikq2MbDkYEA==} + + '@solana/codecs-data-structures@2.0.0-experimental.8618508': + resolution: {integrity: sha512-sLpjL9sqzaDdkloBPV61Rht1tgaKq98BCtIKRuyscIrmVPu3wu0Bavk2n/QekmUzaTsj7K1pVSniM0YqCdnEBw==} + + '@solana/codecs-numbers@2.0.0-experimental.8618508': + resolution: {integrity: sha512-EXQKfzFr3CkKKNzKSZPOOOzchXsFe90TVONWsSnVkonO9z+nGKALE0/L9uBmIFGgdzhhU9QQVFvxBMclIDJo2Q==} + + '@solana/codecs-strings@2.0.0-experimental.8618508': + resolution: {integrity: sha512-b2yhinr1+oe+JDmnnsV0641KQqqDG8AQ16Z/x7GVWO+AWHMpRlHWVXOq8U1yhPMA4VXxl7i+D+C6ql0VGFp0GA==} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + + '@solana/options@2.0.0-experimental.8618508': + resolution: {integrity: sha512-fy/nIRAMC3QHvnKi63KEd86Xr/zFBVxNW4nEpVEU2OT0gCEKwHY4Z55YHf7XujhyuM3PNpiBKg/YYw5QlRU4vg==} + + '@solana/spl-token-metadata@0.1.2': + resolution: {integrity: sha512-hJYnAJNkDrtkE2Q41YZhCpeOGU/0JgRFXbtrtOuGGeKc3pkEUHB9DDoxZAxx+XRno13GozUleyBi0qypz4c3bw==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.87.6 + + '@solana/spl-token@0.3.11': + resolution: {integrity: sha512-bvohO3rIMSVL24Pb+I4EYTJ6cL82eFpInEXD/I8K8upOGjpqHsKUoAempR/RnUlI1qSFNyFlWJfu6MNUgfbCQQ==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.88.0 + + '@solana/spl-type-length-value@0.1.0': + resolution: {integrity: sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA==} + engines: {node: '>=16'} + + '@solana/web3.js@1.92.3': + resolution: {integrity: sha512-NVBWvb9zdJIAx6X+caXaIICCEQfQaQ8ygykCjJW4u2z/sIKcvPj3ZIIllnx0MWMc3IxGq15ozGYDOQIMbwUcHw==} + + '@solana/web3.js@1.95.3': + resolution: {integrity: sha512-O6rPUN0w2fkNqx/Z3QJMB9L225Ex10PRDH8bTaIUPZXMPV0QP8ZpPvjQnXK+upUczlRgzHzd6SjKIha1p+I6og==} + + '@swc/helpers@0.5.13': + resolution: {integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==} + + '@types/chai@4.3.12': + resolution: {integrity: sha512-zNKDHG/1yxm8Il6uCCVsm+dRdEsJlFoDu73X17y09bId6UwoYww+vFBsAcRzl8knM1sab3Dp1VRikFQwDOtDDw==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/mocha@9.1.1': + resolution: {integrity: sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==} + + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + + '@types/node@14.18.63': + resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} + + '@types/node@22.6.0': + resolution: {integrity: sha512-QyR8d5bmq+eR72TwQDfujwShHMcIrWIYsaQFtXRE58MHPTEKUNxjxvl0yS0qPMds5xbSDWtp7ZpvGFtd7dfMdQ==} + + '@types/pbkdf2@3.1.2': + resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} + + '@types/secp256k1@4.0.6': + resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} + + '@types/uuid@8.3.4': + resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + + '@types/ws@7.4.7': + resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} + + '@types/ws@8.5.12': + resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} + + '@ungap/promise-all-settled@1.1.2': + resolution: {integrity: sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==} + + JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + + agentkeepalive@4.5.0: + resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} + engines: {node: '>= 8.0.0'} + + ansi-colors@4.1.1: + resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + arrify@1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + + assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base-x@3.0.10: + resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bigint-buffer@1.1.5: + resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} + engines: {node: '>= 10.0.0'} + + bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + + bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + borsh@0.7.0: + resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + + browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + + bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + + bs58check@2.1.2: + resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer-layout@1.2.2: + resolution: {integrity: sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==} + engines: {node: '>=4.5'} + + buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bufferutil@4.0.8: + resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} + engines: {node: '>=6.14.2'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + chai@4.4.1: + resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + + chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + + cipher-base@1.0.4: + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + + create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + + cross-fetch@3.1.8: + resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} + + crypto-hash@1.3.0: + resolution: {integrity: sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==} + engines: {node: '>=8'} + + debug@4.3.3: + resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + + deep-eql@4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + engines: {node: '>=6'} + + delay@5.0.0: + resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} + engines: {node: '>=10'} + + diff@3.5.0: + resolution: {integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==} + engines: {node: '>=0.3.1'} + + diff@5.0.0: + resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} + engines: {node: '>=0.3.1'} + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + + elliptic@6.5.5: + resolution: {integrity: sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + + es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + ethereum-cryptography@0.1.3: + resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + + eyes@0.1.8: + resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} + engines: {node: '> 0.1.90'} + + fast-stable-stringify@1.0.0: + resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} + + fastestsmallesttextencoderdecoder@1.0.22: + resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@7.2.0: + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + deprecated: Glob versions prior to v9 are no longer supported + + growl@1.10.5: + resolution: {integrity: sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==} + engines: {node: '>=4.x'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hash-base@3.1.0: + resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} + engines: {node: '>=4'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isomorphic-ws@4.0.1: + resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} + peerDependencies: + ws: '*' + + jayson@4.1.2: + resolution: {integrity: sha512-5nzMWDHy6f+koZOuYsArh2AXs73NfWYVlFyJJuCedr93GpY+Ku8qq10ropSXVfHK+H0T6paA88ww+/dV+1fBNA==} + engines: {node: '>=8'} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + + keccak@3.0.4: + resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} + engines: {node: '>=10.0.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@4.2.1: + resolution: {integrity: sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==} + engines: {node: '>=10'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mocha@9.2.2: + resolution: {integrity: sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==} + engines: {node: '>= 12.0.0'} + hasBin: true + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.1: + resolution: {integrity: sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + + node-addon-api@2.0.2: + resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-gyp-build@4.8.2: + resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + + pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + + rpc-websockets@7.10.0: + resolution: {integrity: sha512-cemZ6RiDtYZpPiBzYijdOrkQQzmBCmug0E9SdRH2gIUNT15ql4mwCYWIp0VnSZq6Qrw/JkGUygp4PrK1y9KfwQ==} + + rpc-websockets@8.0.1: + resolution: {integrity: sha512-PptrPRK40uQvifq5sCcObmqInVcZXhy+RRrirzdE5KUPvDI47y1wPvfckD2QzqngOU9xaPW/dT+G+b+wj6M1MQ==} + + rpc-websockets@9.0.2: + resolution: {integrity: sha512-YzggvfItxMY3Lwuax5rC18inhbjJv9Py7JXRHxTIi94JOLrqBsSsUUc5bbl5W6c11tXhdfpDPK0KzBhoGe8jjw==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + scrypt-js@3.0.1: + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + + secp256k1@4.0.3: + resolution: {integrity: sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==} + engines: {node: '>=10.0.0'} + + serialize-javascript@6.0.0: + resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + superstruct@0.15.5: + resolution: {integrity: sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==} + + superstruct@1.0.4: + resolution: {integrity: sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==} + engines: {node: '>=14.0.0'} + + superstruct@2.0.2: + resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} + engines: {node: '>=14.0.0'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + text-encoding-utf-8@1.0.2: + resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toml@3.0.0: + resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + ts-mocha@8.0.0: + resolution: {integrity: sha512-Kou1yxTlubLnD5C3unlCVO7nh0HERTezjoVhVw/M5S1SqoUec0WgllQvPk3vzPMc6by8m6xD1uR1yRf8lnVUbA==} + engines: {node: '>= 6.X.X'} + hasBin: true + peerDependencies: + mocha: ^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X + + ts-node@7.0.1: + resolution: {integrity: sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==} + engines: {node: '>=4.2.0'} + hasBin: true + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + utf-8-validate@5.0.10: + resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} + engines: {node: '>=6.14.2'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + workerpool@6.2.0: + resolution: {integrity: sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yargs-parser@20.2.4: + resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} + engines: {node: '>=10'} + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yn@2.0.0: + resolution: {integrity: sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==} + engines: {node: '>=4'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@babel/runtime@7.25.6': dependencies: regenerator-runtime: 0.14.1 - dev: false - /@coral-xyz/anchor@0.29.0: - resolution: {integrity: sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA==} - engines: {node: '>=11'} + '@coral-xyz/anchor@0.29.0': dependencies: '@coral-xyz/borsh': 0.29.0(@solana/web3.js@1.95.3) '@noble/hashes': 1.5.0 @@ -91,34 +913,20 @@ packages: - bufferutil - encoding - utf-8-validate - dev: false - /@coral-xyz/borsh@0.29.0(@solana/web3.js@1.95.3): - resolution: {integrity: sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ==} - engines: {node: '>=10'} - peerDependencies: - '@solana/web3.js': ^1.68.0 + '@coral-xyz/borsh@0.29.0(@solana/web3.js@1.95.3)': dependencies: '@solana/web3.js': 1.95.3 bn.js: 5.2.1 buffer-layout: 1.2.2 - dev: false - /@noble/curves@1.6.0: - resolution: {integrity: sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==} - engines: {node: ^14.21.3 || >=16} + '@noble/curves@1.6.0': dependencies: '@noble/hashes': 1.5.0 - dev: false - /@noble/hashes@1.5.0: - resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==} - engines: {node: ^14.21.3 || >=16} - dev: false + '@noble/hashes@1.5.0': {} - /@solana/buffer-layout-utils@0.2.0: - resolution: {integrity: sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==} - engines: {node: '>= 10'} + '@solana/buffer-layout-utils@0.2.0': dependencies: '@solana/buffer-layout': 4.0.1 '@solana/web3.js': 1.95.3 @@ -128,54 +936,34 @@ packages: - bufferutil - encoding - utf-8-validate - dev: false - /@solana/buffer-layout@4.0.1: - resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} - engines: {node: '>=5.10'} + '@solana/buffer-layout@4.0.1': dependencies: buffer: 6.0.3 - dev: false - /@solana/codecs-core@2.0.0-experimental.8618508: - resolution: {integrity: sha512-JCz7mKjVKtfZxkuDtwMAUgA7YvJcA2BwpZaA1NOLcted4OMC4Prwa3DUe3f3181ixPYaRyptbF0Ikq2MbDkYEA==} - dev: false + '@solana/codecs-core@2.0.0-experimental.8618508': {} - /@solana/codecs-data-structures@2.0.0-experimental.8618508: - resolution: {integrity: sha512-sLpjL9sqzaDdkloBPV61Rht1tgaKq98BCtIKRuyscIrmVPu3wu0Bavk2n/QekmUzaTsj7K1pVSniM0YqCdnEBw==} + '@solana/codecs-data-structures@2.0.0-experimental.8618508': dependencies: '@solana/codecs-core': 2.0.0-experimental.8618508 '@solana/codecs-numbers': 2.0.0-experimental.8618508 - dev: false - /@solana/codecs-numbers@2.0.0-experimental.8618508: - resolution: {integrity: sha512-EXQKfzFr3CkKKNzKSZPOOOzchXsFe90TVONWsSnVkonO9z+nGKALE0/L9uBmIFGgdzhhU9QQVFvxBMclIDJo2Q==} + '@solana/codecs-numbers@2.0.0-experimental.8618508': dependencies: '@solana/codecs-core': 2.0.0-experimental.8618508 - dev: false - /@solana/codecs-strings@2.0.0-experimental.8618508(fastestsmallesttextencoderdecoder@1.0.22): - resolution: {integrity: sha512-b2yhinr1+oe+JDmnnsV0641KQqqDG8AQ16Z/x7GVWO+AWHMpRlHWVXOq8U1yhPMA4VXxl7i+D+C6ql0VGFp0GA==} - peerDependencies: - fastestsmallesttextencoderdecoder: ^1.0.22 + '@solana/codecs-strings@2.0.0-experimental.8618508(fastestsmallesttextencoderdecoder@1.0.22)': dependencies: '@solana/codecs-core': 2.0.0-experimental.8618508 '@solana/codecs-numbers': 2.0.0-experimental.8618508 fastestsmallesttextencoderdecoder: 1.0.22 - dev: false - /@solana/options@2.0.0-experimental.8618508: - resolution: {integrity: sha512-fy/nIRAMC3QHvnKi63KEd86Xr/zFBVxNW4nEpVEU2OT0gCEKwHY4Z55YHf7XujhyuM3PNpiBKg/YYw5QlRU4vg==} + '@solana/options@2.0.0-experimental.8618508': dependencies: '@solana/codecs-core': 2.0.0-experimental.8618508 '@solana/codecs-numbers': 2.0.0-experimental.8618508 - dev: false - /@solana/spl-token-metadata@0.1.2(@solana/web3.js@1.92.3)(fastestsmallesttextencoderdecoder@1.0.22): - resolution: {integrity: sha512-hJYnAJNkDrtkE2Q41YZhCpeOGU/0JgRFXbtrtOuGGeKc3pkEUHB9DDoxZAxx+XRno13GozUleyBi0qypz4c3bw==} - engines: {node: '>=16'} - peerDependencies: - '@solana/web3.js': ^1.87.6 + '@solana/spl-token-metadata@0.1.2(@solana/web3.js@1.92.3)(fastestsmallesttextencoderdecoder@1.0.22)': dependencies: '@solana/codecs-core': 2.0.0-experimental.8618508 '@solana/codecs-data-structures': 2.0.0-experimental.8618508 @@ -186,13 +974,8 @@ packages: '@solana/web3.js': 1.92.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - dev: false - /@solana/spl-token@0.3.11(@solana/web3.js@1.92.3)(fastestsmallesttextencoderdecoder@1.0.22): - resolution: {integrity: sha512-bvohO3rIMSVL24Pb+I4EYTJ6cL82eFpInEXD/I8K8upOGjpqHsKUoAempR/RnUlI1qSFNyFlWJfu6MNUgfbCQQ==} - engines: {node: '>=16'} - peerDependencies: - '@solana/web3.js': ^1.88.0 + '@solana/spl-token@0.3.11(@solana/web3.js@1.92.3)(fastestsmallesttextencoderdecoder@1.0.22)': dependencies: '@solana/buffer-layout': 4.0.1 '@solana/buffer-layout-utils': 0.2.0 @@ -204,17 +987,12 @@ packages: - encoding - fastestsmallesttextencoderdecoder - utf-8-validate - dev: false - /@solana/spl-type-length-value@0.1.0: - resolution: {integrity: sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA==} - engines: {node: '>=16'} + '@solana/spl-type-length-value@0.1.0': dependencies: buffer: 6.0.3 - dev: false - /@solana/web3.js@1.92.3: - resolution: {integrity: sha512-NVBWvb9zdJIAx6X+caXaIICCEQfQaQ8ygykCjJW4u2z/sIKcvPj3ZIIllnx0MWMc3IxGq15ozGYDOQIMbwUcHw==} + '@solana/web3.js@1.92.3': dependencies: '@babel/runtime': 7.25.6 '@noble/curves': 1.6.0 @@ -235,10 +1013,8 @@ packages: - bufferutil - encoding - utf-8-validate - dev: false - /@solana/web3.js@1.95.3: - resolution: {integrity: sha512-O6rPUN0w2fkNqx/Z3QJMB9L225Ex10PRDH8bTaIUPZXMPV0QP8ZpPvjQnXK+upUczlRgzHzd6SjKIha1p+I6og==} + '@solana/web3.js@1.95.3': dependencies: '@babel/runtime': 7.25.6 '@noble/curves': 1.6.0 @@ -259,214 +1035,124 @@ packages: - bufferutil - encoding - utf-8-validate - dev: false - /@swc/helpers@0.5.13: - resolution: {integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==} + '@swc/helpers@0.5.13': dependencies: tslib: 2.7.0 - dev: false - /@types/chai@4.3.12: - resolution: {integrity: sha512-zNKDHG/1yxm8Il6uCCVsm+dRdEsJlFoDu73X17y09bId6UwoYww+vFBsAcRzl8knM1sab3Dp1VRikFQwDOtDDw==} - dev: false + '@types/chai@4.3.12': {} - /@types/connect@3.4.38: - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/connect@3.4.38': dependencies: '@types/node': 22.6.0 - dev: false - /@types/json5@0.0.29: - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - requiresBuild: true - dev: false + '@types/json5@0.0.29': optional: true - /@types/mocha@9.1.1: - resolution: {integrity: sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==} - dev: false + '@types/mocha@9.1.1': {} - /@types/node@12.20.55: - resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - dev: false + '@types/node@12.20.55': {} - /@types/node@14.18.63: - resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} - dev: false + '@types/node@14.18.63': {} - /@types/node@22.6.0: - resolution: {integrity: sha512-QyR8d5bmq+eR72TwQDfujwShHMcIrWIYsaQFtXRE58MHPTEKUNxjxvl0yS0qPMds5xbSDWtp7ZpvGFtd7dfMdQ==} + '@types/node@22.6.0': dependencies: undici-types: 6.19.8 - dev: false - /@types/pbkdf2@3.1.2: - resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} + '@types/pbkdf2@3.1.2': dependencies: '@types/node': 22.6.0 - dev: false - /@types/secp256k1@4.0.6: - resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} + '@types/secp256k1@4.0.6': dependencies: '@types/node': 22.6.0 - dev: false - /@types/uuid@8.3.4: - resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} - dev: false + '@types/uuid@8.3.4': {} - /@types/ws@7.4.7: - resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} + '@types/ws@7.4.7': dependencies: '@types/node': 22.6.0 - dev: false - /@types/ws@8.5.12: - resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} + '@types/ws@8.5.12': dependencies: '@types/node': 22.6.0 - dev: false - /@ungap/promise-all-settled@1.1.2: - resolution: {integrity: sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==} - dev: false + '@ungap/promise-all-settled@1.1.2': {} - /JSONStream@1.3.5: - resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} - hasBin: true + JSONStream@1.3.5: dependencies: jsonparse: 1.3.1 through: 2.3.8 - dev: false - /agentkeepalive@4.5.0: - resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} - engines: {node: '>= 8.0.0'} + agentkeepalive@4.5.0: dependencies: humanize-ms: 1.2.1 - dev: false - /ansi-colors@4.1.1: - resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} - engines: {node: '>=6'} - dev: false + ansi-colors@4.1.1: {} - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: false + ansi-regex@5.0.1: {} - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - dev: false - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: false - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: false + argparse@2.0.1: {} - /arrify@1.0.1: - resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} - engines: {node: '>=0.10.0'} - dev: false + arrify@1.0.1: {} - /assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - dev: false + assertion-error@1.1.0: {} - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: false + balanced-match@1.0.2: {} - /base-x@3.0.10: - resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==} + base-x@3.0.10: dependencies: safe-buffer: 5.2.1 - dev: false - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: false + base64-js@1.5.1: {} - /bigint-buffer@1.1.5: - resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} - engines: {node: '>= 10.0.0'} - requiresBuild: true + bigint-buffer@1.1.5: dependencies: bindings: 1.5.0 - dev: false - /bignumber.js@9.1.2: - resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} - dev: false + bignumber.js@9.1.2: {} - /binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - dev: false + binary-extensions@2.3.0: {} - /bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + bindings@1.5.0: dependencies: file-uri-to-path: 1.0.0 - dev: false - /blakejs@1.2.1: - resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} - dev: false + blakejs@1.2.1: {} - /bn.js@4.12.0: - resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} - dev: false + bn.js@4.12.0: {} - /bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - dev: false + bn.js@5.2.1: {} - /borsh@0.7.0: - resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + borsh@0.7.0: dependencies: bn.js: 5.2.1 bs58: 4.0.1 text-encoding-utf-8: 1.0.2 - dev: false - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: false - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} + braces@3.0.2: dependencies: fill-range: 7.0.1 - dev: false - /brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - dev: false + brorand@1.1.0: {} - /browser-stdout@1.3.1: - resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - dev: false + browser-stdout@1.3.1: {} - /browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + browserify-aes@1.2.0: dependencies: buffer-xor: 1.0.3 cipher-base: 1.0.4 @@ -474,58 +1160,35 @@ packages: evp_bytestokey: 1.0.3 inherits: 2.0.4 safe-buffer: 5.2.1 - dev: false - /bs58@4.0.1: - resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + bs58@4.0.1: dependencies: base-x: 3.0.10 - dev: false - /bs58check@2.1.2: - resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} + bs58check@2.1.2: dependencies: bs58: 4.0.1 create-hash: 1.2.0 safe-buffer: 5.2.1 - dev: false - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: false + buffer-from@1.1.2: {} - /buffer-layout@1.2.2: - resolution: {integrity: sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==} - engines: {node: '>=4.5'} - dev: false + buffer-layout@1.2.2: {} - /buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} - dev: false + buffer-xor@1.0.3: {} - /buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + buffer@6.0.3: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: false - /bufferutil@4.0.8: - resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} - engines: {node: '>=6.14.2'} - requiresBuild: true + bufferutil@4.0.8: dependencies: node-gyp-build: 4.8.2 - dev: false - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: false + camelcase@6.3.0: {} - /chai@4.4.1: - resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} - engines: {node: '>=4'} + chai@4.4.1: dependencies: assertion-error: 1.1.0 check-error: 1.0.3 @@ -534,25 +1197,17 @@ packages: loupe: 2.3.7 pathval: 1.1.1 type-detect: 4.0.8 - dev: false - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: false - /check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + check-error@1.0.3: dependencies: get-func-name: 2.0.2 - dev: false - /chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} + chokidar@3.5.3: dependencies: anymatch: 3.1.3 braces: 3.0.2 @@ -563,54 +1218,37 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: false - /cipher-base@1.0.4: - resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + cipher-base@1.0.4: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 - dev: false - /cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + cliui@7.0.4: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: false - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + color-convert@2.0.1: dependencies: color-name: 1.1.4 - dev: false - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: false + color-name@1.1.4: {} - /commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: false + commander@2.20.3: {} - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: false + concat-map@0.0.1: {} - /create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + create-hash@1.2.0: dependencies: cipher-base: 1.0.4 inherits: 2.0.4 md5.js: 1.3.5 ripemd160: 2.0.2 sha.js: 2.4.11 - dev: false - /create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + create-hmac@1.1.7: dependencies: cipher-base: 1.0.4 create-hash: 1.2.0 @@ -618,70 +1256,38 @@ packages: ripemd160: 2.0.2 safe-buffer: 5.2.1 sha.js: 2.4.11 - dev: false - /cross-fetch@3.1.8: - resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} + cross-fetch@3.1.8: dependencies: node-fetch: 2.7.0 transitivePeerDependencies: - encoding - dev: false - /crypto-hash@1.3.0: - resolution: {integrity: sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==} - engines: {node: '>=8'} - dev: false + crypto-hash@1.3.0: {} - /debug@4.3.3(supports-color@8.1.1): - resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + debug@4.3.3(supports-color@8.1.1): dependencies: ms: 2.1.2 supports-color: 8.1.1 - dev: false - - /decamelize@4.0.0: - resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} - engines: {node: '>=10'} - dev: false - /deep-eql@4.1.3: - resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} - engines: {node: '>=6'} + decamelize@4.0.0: {} + + deep-eql@4.1.3: dependencies: type-detect: 4.0.8 - dev: false - /delay@5.0.0: - resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} - engines: {node: '>=10'} - dev: false + delay@5.0.0: {} - /diff@3.5.0: - resolution: {integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==} - engines: {node: '>=0.3.1'} - dev: false + diff@3.5.0: {} - /diff@5.0.0: - resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} - engines: {node: '>=0.3.1'} - dev: false + diff@5.0.0: {} - /dot-case@3.0.4: - resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dot-case@3.0.4: dependencies: no-case: 3.0.4 tslib: 2.7.0 - dev: false - /elliptic@6.5.5: - resolution: {integrity: sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==} + elliptic@6.5.5: dependencies: bn.js: 4.12.0 brorand: 1.1.0 @@ -690,34 +1296,20 @@ packages: inherits: 2.0.4 minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - dev: false - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: false + emoji-regex@8.0.0: {} - /es6-promise@4.2.8: - resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} - dev: false + es6-promise@4.2.8: {} - /es6-promisify@5.0.0: - resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + es6-promisify@5.0.0: dependencies: es6-promise: 4.2.8 - dev: false - /escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} - engines: {node: '>=6'} - dev: false + escalade@3.1.2: {} - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: false + escape-string-regexp@4.0.0: {} - /ethereum-cryptography@0.1.3: - resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} + ethereum-cryptography@0.1.3: dependencies: '@types/pbkdf2': 3.1.2 '@types/secp256k1': 4.0.6 @@ -734,91 +1326,49 @@ packages: scrypt-js: 3.0.1 secp256k1: 4.0.3 setimmediate: 1.0.5 - dev: false - /eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - dev: false + eventemitter3@4.0.7: {} - /eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - dev: false + eventemitter3@5.0.1: {} - /evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + evp_bytestokey@1.0.3: dependencies: md5.js: 1.3.5 safe-buffer: 5.2.1 - dev: false - /eyes@0.1.8: - resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} - engines: {node: '> 0.1.90'} - dev: false + eyes@0.1.8: {} - /fast-stable-stringify@1.0.0: - resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} - dev: false + fast-stable-stringify@1.0.0: {} - /fastestsmallesttextencoderdecoder@1.0.22: - resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} - dev: false + fastestsmallesttextencoderdecoder@1.0.22: {} - /file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - dev: false + file-uri-to-path@1.0.0: {} - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} + fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 - dev: false - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} + find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: false - /flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - dev: false + flat@5.0.2: {} - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: false + fs.realpath@1.0.0: {} - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: false + fsevents@2.3.3: optional: true - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: false + get-caller-file@2.0.5: {} - /get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - dev: false + get-func-name@2.0.2: {} - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - dev: false - /glob@7.2.0: - resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} - deprecated: Glob versions prior to v9 are no longer supported + glob@7.2.0: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -826,124 +1376,68 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: false - /growl@1.10.5: - resolution: {integrity: sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==} - engines: {node: '>=4.x'} - dev: false + growl@1.10.5: {} - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: false + has-flag@4.0.0: {} - /hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} + hash-base@3.1.0: dependencies: inherits: 2.0.4 readable-stream: 3.6.2 safe-buffer: 5.2.1 - dev: false - /hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + hash.js@1.1.7: dependencies: inherits: 2.0.4 minimalistic-assert: 1.0.1 - dev: false - /he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - dev: false + he@1.2.0: {} - /hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + hmac-drbg@1.0.1: dependencies: hash.js: 1.1.7 minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - dev: false - /humanize-ms@1.2.1: - resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + humanize-ms@1.2.1: dependencies: ms: 2.1.3 - dev: false - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: false + ieee754@1.2.1: {} - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: false - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: false + inherits@2.0.4: {} - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 - dev: false - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: false + is-extglob@2.1.1: {} - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: false + is-fullwidth-code-point@3.0.0: {} - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - dev: false - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: false + is-number@7.0.0: {} - /is-plain-obj@2.1.0: - resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} - engines: {node: '>=8'} - dev: false + is-plain-obj@2.1.0: {} - /is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - dev: false + is-unicode-supported@0.1.0: {} - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: false + isexe@2.0.0: {} - /isomorphic-ws@4.0.1(ws@7.5.10): - resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} - peerDependencies: - ws: '*' + isomorphic-ws@4.0.1(ws@7.5.10): dependencies: ws: 7.5.10 - dev: false - /jayson@4.1.2: - resolution: {integrity: sha512-5nzMWDHy6f+koZOuYsArh2AXs73NfWYVlFyJJuCedr93GpY+Ku8qq10ropSXVfHK+H0T6paA88ww+/dV+1fBNA==} - engines: {node: '>=8'} - hasBin: true + jayson@4.1.2: dependencies: '@types/connect': 3.4.38 '@types/node': 12.20.55 @@ -960,118 +1454,70 @@ packages: transitivePeerDependencies: - bufferutil - utf-8-validate - dev: false - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true + js-yaml@4.1.0: dependencies: argparse: 2.0.1 - dev: false - /json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - dev: false + json-stringify-safe@5.0.1: {} - /json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true - requiresBuild: true + json5@1.0.2: dependencies: minimist: 1.2.8 - dev: false optional: true - /jsonparse@1.3.1: - resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} - engines: {'0': node >= 0.2.0} - dev: false + jsonparse@1.3.1: {} - /keccak@3.0.4: - resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} - engines: {node: '>=10.0.0'} - requiresBuild: true + keccak@3.0.4: dependencies: node-addon-api: 2.0.2 node-gyp-build: 4.8.2 readable-stream: 3.6.2 - dev: false - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + locate-path@6.0.0: dependencies: p-locate: 5.0.0 - dev: false - /log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} + log-symbols@4.1.0: dependencies: chalk: 4.1.2 is-unicode-supported: 0.1.0 - dev: false - /loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + loupe@2.3.7: dependencies: get-func-name: 2.0.2 - dev: false - /lower-case@2.0.2: - resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lower-case@2.0.2: dependencies: tslib: 2.7.0 - dev: false - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: false + make-error@1.3.6: {} - /md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + md5.js@1.3.5: dependencies: hash-base: 3.1.0 inherits: 2.0.4 safe-buffer: 5.2.1 - dev: false - /minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - dev: false + minimalistic-assert@1.0.1: {} - /minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - dev: false + minimalistic-crypto-utils@1.0.1: {} - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 - dev: false - /minimatch@4.2.1: - resolution: {integrity: sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==} - engines: {node: '>=10'} + minimatch@4.2.1: dependencies: brace-expansion: 1.1.11 - dev: false - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: false + minimist@1.2.8: {} - /mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true + mkdirp@0.5.6: dependencies: minimist: 1.2.8 - dev: false - /mocha@9.2.2: - resolution: {integrity: sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==} - engines: {node: '>= 12.0.0'} - hasBin: true + mocha@9.2.2: dependencies: '@ungap/promise-all-settled': 1.1.2 ansi-colors: 4.1.1 @@ -1097,155 +1543,84 @@ packages: yargs: 16.2.0 yargs-parser: 20.2.4 yargs-unparser: 2.0.0 - dev: false - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: false + ms@2.1.2: {} - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: false + ms@2.1.3: {} - /nanoid@3.3.1: - resolution: {integrity: sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: false + nanoid@3.3.1: {} - /no-case@3.0.4: - resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + no-case@3.0.4: dependencies: lower-case: 2.0.2 tslib: 2.7.0 - dev: false - /node-addon-api@2.0.2: - resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} - dev: false + node-addon-api@2.0.2: {} - /node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 - dev: false - /node-gyp-build@4.8.2: - resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==} - hasBin: true - dev: false + node-gyp-build@4.8.2: {} - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: false + normalize-path@3.0.0: {} - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + once@1.4.0: dependencies: wrappy: 1.0.2 - dev: false - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - dev: false - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + p-locate@5.0.0: dependencies: p-limit: 3.1.0 - dev: false - /pako@2.1.0: - resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} - dev: false + pako@2.1.0: {} - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: false + path-exists@4.0.0: {} - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: false + path-is-absolute@1.0.1: {} - /pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - dev: false + pathval@1.1.1: {} - /pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} - engines: {node: '>=0.12'} + pbkdf2@3.1.2: dependencies: create-hash: 1.2.0 create-hmac: 1.1.7 ripemd160: 2.0.2 safe-buffer: 5.2.1 sha.js: 2.4.11 - dev: false - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: false + picomatch@2.3.1: {} - /prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - dev: false + prettier@2.8.8: {} - /randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 - dev: false - /readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} + readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - dev: false - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + readdirp@3.6.0: dependencies: picomatch: 2.3.1 - dev: false - /regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - dev: false + regenerator-runtime@0.14.1: {} - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: false + require-directory@2.1.1: {} - /ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + ripemd160@2.0.2: dependencies: hash-base: 3.1.0 inherits: 2.0.4 - dev: false - /rpc-websockets@7.10.0: - resolution: {integrity: sha512-cemZ6RiDtYZpPiBzYijdOrkQQzmBCmug0E9SdRH2gIUNT15ql4mwCYWIp0VnSZq6Qrw/JkGUygp4PrK1y9KfwQ==} + rpc-websockets@7.10.0: dependencies: '@babel/runtime': 7.25.6 eventemitter3: 4.0.7 @@ -1254,10 +1629,8 @@ packages: optionalDependencies: bufferutil: 4.0.8 utf-8-validate: 5.0.10 - dev: false - /rpc-websockets@8.0.1: - resolution: {integrity: sha512-PptrPRK40uQvifq5sCcObmqInVcZXhy+RRrirzdE5KUPvDI47y1wPvfckD2QzqngOU9xaPW/dT+G+b+wj6M1MQ==} + rpc-websockets@8.0.1: dependencies: eventemitter3: 4.0.7 uuid: 8.3.2 @@ -1265,10 +1638,8 @@ packages: optionalDependencies: bufferutil: 4.0.8 utf-8-validate: 5.0.10 - dev: false - /rpc-websockets@9.0.2: - resolution: {integrity: sha512-YzggvfItxMY3Lwuax5rC18inhbjJv9Py7JXRHxTIi94JOLrqBsSsUUc5bbl5W6c11tXhdfpDPK0KzBhoGe8jjw==} + rpc-websockets@9.0.2: dependencies: '@swc/helpers': 0.5.13 '@types/uuid': 8.3.4 @@ -1280,165 +1651,93 @@ packages: optionalDependencies: bufferutil: 4.0.8 utf-8-validate: 5.0.10 - dev: false - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: false + safe-buffer@5.2.1: {} - /scrypt-js@3.0.1: - resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} - dev: false + scrypt-js@3.0.1: {} - /secp256k1@4.0.3: - resolution: {integrity: sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==} - engines: {node: '>=10.0.0'} - requiresBuild: true + secp256k1@4.0.3: dependencies: elliptic: 6.5.5 node-addon-api: 2.0.2 node-gyp-build: 4.8.2 - dev: false - /serialize-javascript@6.0.0: - resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + serialize-javascript@6.0.0: dependencies: randombytes: 2.1.0 - dev: false - /setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - dev: false + setimmediate@1.0.5: {} - /sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} - hasBin: true + sha.js@2.4.11: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 - dev: false - /snake-case@3.0.4: - resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + snake-case@3.0.4: dependencies: dot-case: 3.0.4 tslib: 2.7.0 - dev: false - /source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: false - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: false + source-map@0.6.1: {} - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: false - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 - dev: false - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - dev: false - /strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - requiresBuild: true - dev: false + strip-bom@3.0.0: optional: true - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: false + strip-json-comments@3.1.1: {} - /superstruct@0.15.5: - resolution: {integrity: sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==} - dev: false + superstruct@0.15.5: {} - /superstruct@1.0.4: - resolution: {integrity: sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==} - engines: {node: '>=14.0.0'} - dev: false + superstruct@1.0.4: {} - /superstruct@2.0.2: - resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} - engines: {node: '>=14.0.0'} - dev: false + superstruct@2.0.2: {} - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - dev: false - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} + supports-color@8.1.1: dependencies: has-flag: 4.0.0 - dev: false - /text-encoding-utf-8@1.0.2: - resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} - dev: false + text-encoding-utf-8@1.0.2: {} - /through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: false + through@2.3.8: {} - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - dev: false - /toml@3.0.0: - resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} - dev: false + toml@3.0.0: {} - /tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: false + tr46@0.0.3: {} - /ts-mocha@8.0.0(mocha@9.2.2): - resolution: {integrity: sha512-Kou1yxTlubLnD5C3unlCVO7nh0HERTezjoVhVw/M5S1SqoUec0WgllQvPk3vzPMc6by8m6xD1uR1yRf8lnVUbA==} - engines: {node: '>= 6.X.X'} - hasBin: true - peerDependencies: - mocha: ^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X + ts-mocha@8.0.0(mocha@9.2.2): dependencies: mocha: 9.2.2 ts-node: 7.0.1 optionalDependencies: tsconfig-paths: 3.15.0 - dev: false - /ts-node@7.0.1: - resolution: {integrity: sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==} - engines: {node: '>=4.2.0'} - hasBin: true + ts-node@7.0.1: dependencies: arrify: 1.0.1 buffer-from: 1.1.2 @@ -1448,148 +1747,73 @@ packages: mkdirp: 0.5.6 source-map-support: 0.5.21 yn: 2.0.0 - dev: false - /tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - requiresBuild: true + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 json5: 1.0.2 minimist: 1.2.8 strip-bom: 3.0.0 - dev: false optional: true - /tslib@2.7.0: - resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} - dev: false + tslib@2.7.0: {} - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - dev: false + type-detect@4.0.8: {} - /typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: false + typescript@4.9.5: {} - /undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - dev: false + undici-types@6.19.8: {} - /utf-8-validate@5.0.10: - resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} - engines: {node: '>=6.14.2'} - requiresBuild: true + utf-8-validate@5.0.10: dependencies: node-gyp-build: 4.8.2 - dev: false - /util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: false + util-deprecate@1.0.2: {} - /uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - dev: false + uuid@8.3.2: {} - /webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: false + webidl-conversions@3.0.1: {} - /whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 - dev: false - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + which@2.0.2: dependencies: isexe: 2.0.0 - dev: false - /workerpool@6.2.0: - resolution: {integrity: sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==} - dev: false + workerpool@6.2.0: {} - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: false - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: false + wrappy@1.0.2: {} - /ws@7.5.10: - resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false + ws@7.5.10: {} - /ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true + ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): dependencies: bufferutil: 4.0.8 utf-8-validate: 5.0.10 - dev: false - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: false + y18n@5.0.8: {} - /yargs-parser@20.2.4: - resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} - engines: {node: '>=10'} - dev: false + yargs-parser@20.2.4: {} - /yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} - dev: false + yargs-parser@20.2.9: {} - /yargs-unparser@2.0.0: - resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} - engines: {node: '>=10'} + yargs-unparser@2.0.0: dependencies: camelcase: 6.3.0 decamelize: 4.0.0 flat: 5.0.2 is-plain-obj: 2.1.0 - dev: false - /yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} + yargs@16.2.0: dependencies: cliui: 7.0.4 escalade: 3.1.2 @@ -1598,14 +1822,7 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 20.2.9 - dev: false - /yn@2.0.0: - resolution: {integrity: sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==} - engines: {node: '>=4'} - dev: false + yn@2.0.0: {} - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: false + yocto-queue@0.1.0: {} diff --git a/contracts/programs/log-read-test/src/event.rs b/contracts/programs/log-read-test/src/event.rs index fe49922f4..64c4e91c0 100644 --- a/contracts/programs/log-read-test/src/event.rs +++ b/contracts/programs/log-read-test/src/event.rs @@ -4,4 +4,4 @@ use anchor_lang::prelude::*; pub struct TestEvent { pub str_val: String, pub u64_value: u64, -} \ No newline at end of file +} diff --git a/contracts/programs/log-read-test/src/lib.rs b/contracts/programs/log-read-test/src/lib.rs index 295f910cf..e2acf26db 100644 --- a/contracts/programs/log-read-test/src/lib.rs +++ b/contracts/programs/log-read-test/src/lib.rs @@ -13,7 +13,7 @@ pub mod log_read_test { str_val: "Hello, World!".to_string(), u64_value: value, }); - + Ok(()) } } @@ -22,4 +22,4 @@ pub mod log_read_test { pub struct Initialization<'info> { pub authority: Signer<'info>, pub system_program: Program<'info, System>, -} \ No newline at end of file +} diff --git a/integration-tests/smoke/event_loader_test.go b/integration-tests/smoke/event_loader_test.go index 689610303..7ced52a7f 100644 --- a/integration-tests/smoke/event_loader_test.go +++ b/integration-tests/smoke/event_loader_test.go @@ -31,11 +31,6 @@ import ( "github.com/smartcontractkit/chainlink-solana/integration-tests/utils" ) -type testConfig struct { - PrivateKey string - PublicKey string -} - const programPubKey = "J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4" func TestEventLoader(t *testing.T) { @@ -56,6 +51,7 @@ func TestEventLoader(t *testing.T) { rpcURL, wsURL := setupTestValidator(t, privateKey.PublicKey().String()) rpcClient := rpc.New(rpcURL) wsClient, err := ws.Connect(ctx, wsURL) + require.NoError(t, err) defer wsClient.Close() diff --git a/pkg/monitoring/chain_reader.go b/pkg/monitoring/chain_reader.go index eb4d4b8e5..09712d867 100644 --- a/pkg/monitoring/chain_reader.go +++ b/pkg/monitoring/chain_reader.go @@ -9,7 +9,6 @@ import ( pkgSolana "github.com/smartcontractkit/chainlink-solana/pkg/solana" ) -//go:generate mockery --name ChainReader --output ./mocks/ type ChainReader interface { GetState(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType) (state pkgSolana.State, blockHeight uint64, err error) GetLatestTransmission(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType) (answer pkgSolana.Answer, blockHeight uint64, err error) diff --git a/pkg/monitoring/metrics/feedbalances.go b/pkg/monitoring/metrics/feedbalances.go index c56c86a75..54e856ad4 100644 --- a/pkg/monitoring/metrics/feedbalances.go +++ b/pkg/monitoring/metrics/feedbalances.go @@ -8,8 +8,6 @@ import ( commonMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring" ) -//go:generate mockery --name FeedBalances --output ./mocks/ - type FeedBalances interface { Exists(balanceAccountName string) (*prometheus.GaugeVec, bool) SetBalance(balance uint64, balanceAccountName string, feedInput FeedInput) diff --git a/pkg/monitoring/metrics/fees.go b/pkg/monitoring/metrics/fees.go index 883b69485..05aed3fc9 100644 --- a/pkg/monitoring/metrics/fees.go +++ b/pkg/monitoring/metrics/fees.go @@ -7,8 +7,6 @@ import ( "github.com/smartcontractkit/chainlink-solana/pkg/solana/fees" ) -//go:generate mockery --name Fees --output ./mocks/ - type Fees interface { Set(txFee uint64, computeUnitPrice fees.ComputeUnitPrice, feedInput FeedInput) Cleanup(feedInput FeedInput) diff --git a/pkg/monitoring/metrics/mocks/FeedBalances.go b/pkg/monitoring/metrics/mocks/FeedBalances.go deleted file mode 100644 index ded286e81..000000000 --- a/pkg/monitoring/metrics/mocks/FeedBalances.go +++ /dev/null @@ -1,69 +0,0 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. - -package mocks - -import ( - metrics "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics" - mock "github.com/stretchr/testify/mock" - - prometheus "github.com/prometheus/client_golang/prometheus" -) - -// FeedBalances is an autogenerated mock type for the FeedBalances type -type FeedBalances struct { - mock.Mock -} - -// Cleanup provides a mock function with given fields: balanceAccountName, feedInput -func (_m *FeedBalances) Cleanup(balanceAccountName string, feedInput metrics.FeedInput) { - _m.Called(balanceAccountName, feedInput) -} - -// Exists provides a mock function with given fields: balanceAccountName -func (_m *FeedBalances) Exists(balanceAccountName string) (*prometheus.GaugeVec, bool) { - ret := _m.Called(balanceAccountName) - - if len(ret) == 0 { - panic("no return value specified for Exists") - } - - var r0 *prometheus.GaugeVec - var r1 bool - if rf, ok := ret.Get(0).(func(string) (*prometheus.GaugeVec, bool)); ok { - return rf(balanceAccountName) - } - if rf, ok := ret.Get(0).(func(string) *prometheus.GaugeVec); ok { - r0 = rf(balanceAccountName) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*prometheus.GaugeVec) - } - } - - if rf, ok := ret.Get(1).(func(string) bool); ok { - r1 = rf(balanceAccountName) - } else { - r1 = ret.Get(1).(bool) - } - - return r0, r1 -} - -// SetBalance provides a mock function with given fields: balance, balanceAccountName, feedInput -func (_m *FeedBalances) SetBalance(balance uint64, balanceAccountName string, feedInput metrics.FeedInput) { - _m.Called(balance, balanceAccountName, feedInput) -} - -// NewFeedBalances creates a new instance of FeedBalances. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewFeedBalances(t interface { - mock.TestingT - Cleanup(func()) -}) *FeedBalances { - mock := &FeedBalances{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/monitoring/metrics/mocks/Fees.go b/pkg/monitoring/metrics/mocks/Fees.go index e435cfabd..3bb621ec5 100644 --- a/pkg/monitoring/metrics/mocks/Fees.go +++ b/pkg/monitoring/metrics/mocks/Fees.go @@ -14,16 +14,82 @@ type Fees struct { mock.Mock } +type Fees_Expecter struct { + mock *mock.Mock +} + +func (_m *Fees) EXPECT() *Fees_Expecter { + return &Fees_Expecter{mock: &_m.Mock} +} + // Cleanup provides a mock function with given fields: feedInput func (_m *Fees) Cleanup(feedInput metrics.FeedInput) { _m.Called(feedInput) } +// Fees_Cleanup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Cleanup' +type Fees_Cleanup_Call struct { + *mock.Call +} + +// Cleanup is a helper method to define mock.On call +// - feedInput metrics.FeedInput +func (_e *Fees_Expecter) Cleanup(feedInput interface{}) *Fees_Cleanup_Call { + return &Fees_Cleanup_Call{Call: _e.mock.On("Cleanup", feedInput)} +} + +func (_c *Fees_Cleanup_Call) Run(run func(feedInput metrics.FeedInput)) *Fees_Cleanup_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(metrics.FeedInput)) + }) + return _c +} + +func (_c *Fees_Cleanup_Call) Return() *Fees_Cleanup_Call { + _c.Call.Return() + return _c +} + +func (_c *Fees_Cleanup_Call) RunAndReturn(run func(metrics.FeedInput)) *Fees_Cleanup_Call { + _c.Call.Return(run) + return _c +} + // Set provides a mock function with given fields: txFee, computeUnitPrice, feedInput func (_m *Fees) Set(txFee uint64, computeUnitPrice fees.ComputeUnitPrice, feedInput metrics.FeedInput) { _m.Called(txFee, computeUnitPrice, feedInput) } +// Fees_Set_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Set' +type Fees_Set_Call struct { + *mock.Call +} + +// Set is a helper method to define mock.On call +// - txFee uint64 +// - computeUnitPrice fees.ComputeUnitPrice +// - feedInput metrics.FeedInput +func (_e *Fees_Expecter) Set(txFee interface{}, computeUnitPrice interface{}, feedInput interface{}) *Fees_Set_Call { + return &Fees_Set_Call{Call: _e.mock.On("Set", txFee, computeUnitPrice, feedInput)} +} + +func (_c *Fees_Set_Call) Run(run func(txFee uint64, computeUnitPrice fees.ComputeUnitPrice, feedInput metrics.FeedInput)) *Fees_Set_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(uint64), args[1].(fees.ComputeUnitPrice), args[2].(metrics.FeedInput)) + }) + return _c +} + +func (_c *Fees_Set_Call) Return() *Fees_Set_Call { + _c.Call.Return() + return _c +} + +func (_c *Fees_Set_Call) RunAndReturn(run func(uint64, fees.ComputeUnitPrice, metrics.FeedInput)) *Fees_Set_Call { + _c.Call.Return(run) + return _c +} + // NewFees creates a new instance of Fees. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewFees(t interface { diff --git a/pkg/monitoring/metrics/mocks/NetworkFees.go b/pkg/monitoring/metrics/mocks/NetworkFees.go deleted file mode 100644 index 3b27dbd93..000000000 --- a/pkg/monitoring/metrics/mocks/NetworkFees.go +++ /dev/null @@ -1,37 +0,0 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. - -package mocks - -import ( - metrics "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics" - mock "github.com/stretchr/testify/mock" -) - -// NetworkFees is an autogenerated mock type for the NetworkFees type -type NetworkFees struct { - mock.Mock -} - -// Cleanup provides a mock function with given fields: -func (_m *NetworkFees) Cleanup() { - _m.Called() -} - -// Set provides a mock function with given fields: slot, chain -func (_m *NetworkFees) Set(slot metrics.NetworkFeesInput, chain string) { - _m.Called(slot, chain) -} - -// NewNetworkFees creates a new instance of NetworkFees. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewNetworkFees(t interface { - mock.TestingT - Cleanup(func()) -}) *NetworkFees { - mock := &NetworkFees{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/monitoring/metrics/mocks/NodeBalances.go b/pkg/monitoring/metrics/mocks/NodeBalances.go deleted file mode 100644 index bbf9aa4b8..000000000 --- a/pkg/monitoring/metrics/mocks/NodeBalances.go +++ /dev/null @@ -1,34 +0,0 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. - -package mocks - -import mock "github.com/stretchr/testify/mock" - -// NodeBalances is an autogenerated mock type for the NodeBalances type -type NodeBalances struct { - mock.Mock -} - -// Cleanup provides a mock function with given fields: address, operator -func (_m *NodeBalances) Cleanup(address string, operator string) { - _m.Called(address, operator) -} - -// SetBalance provides a mock function with given fields: balance, address, operator -func (_m *NodeBalances) SetBalance(balance uint64, address string, operator string) { - _m.Called(balance, address, operator) -} - -// NewNodeBalances creates a new instance of NodeBalances. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewNodeBalances(t interface { - mock.TestingT - Cleanup(func()) -}) *NodeBalances { - mock := &NodeBalances{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/monitoring/metrics/mocks/NodeSuccess.go b/pkg/monitoring/metrics/mocks/NodeSuccess.go deleted file mode 100644 index b80b46f59..000000000 --- a/pkg/monitoring/metrics/mocks/NodeSuccess.go +++ /dev/null @@ -1,37 +0,0 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. - -package mocks - -import ( - metrics "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics" - mock "github.com/stretchr/testify/mock" -) - -// NodeSuccess is an autogenerated mock type for the NodeSuccess type -type NodeSuccess struct { - mock.Mock -} - -// Add provides a mock function with given fields: count, i -func (_m *NodeSuccess) Add(count int, i metrics.NodeFeedInput) { - _m.Called(count, i) -} - -// Cleanup provides a mock function with given fields: i -func (_m *NodeSuccess) Cleanup(i metrics.NodeFeedInput) { - _m.Called(i) -} - -// NewNodeSuccess creates a new instance of NodeSuccess. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewNodeSuccess(t interface { - mock.TestingT - Cleanup(func()) -}) *NodeSuccess { - mock := &NodeSuccess{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/monitoring/metrics/mocks/ReportObservations.go b/pkg/monitoring/metrics/mocks/ReportObservations.go deleted file mode 100644 index 814d997eb..000000000 --- a/pkg/monitoring/metrics/mocks/ReportObservations.go +++ /dev/null @@ -1,37 +0,0 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. - -package mocks - -import ( - metrics "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics" - mock "github.com/stretchr/testify/mock" -) - -// ReportObservations is an autogenerated mock type for the ReportObservations type -type ReportObservations struct { - mock.Mock -} - -// Cleanup provides a mock function with given fields: feedInput -func (_m *ReportObservations) Cleanup(feedInput metrics.FeedInput) { - _m.Called(feedInput) -} - -// SetCount provides a mock function with given fields: count, feedInput -func (_m *ReportObservations) SetCount(count uint8, feedInput metrics.FeedInput) { - _m.Called(count, feedInput) -} - -// NewReportObservations creates a new instance of ReportObservations. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewReportObservations(t interface { - mock.TestingT - Cleanup(func()) -}) *ReportObservations { - mock := &ReportObservations{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/monitoring/metrics/mocks/SlotHeight.go b/pkg/monitoring/metrics/mocks/SlotHeight.go deleted file mode 100644 index 22de7542b..000000000 --- a/pkg/monitoring/metrics/mocks/SlotHeight.go +++ /dev/null @@ -1,37 +0,0 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. - -package mocks - -import ( - types "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types" - mock "github.com/stretchr/testify/mock" -) - -// SlotHeight is an autogenerated mock type for the SlotHeight type -type SlotHeight struct { - mock.Mock -} - -// Cleanup provides a mock function with given fields: -func (_m *SlotHeight) Cleanup() { - _m.Called() -} - -// Set provides a mock function with given fields: slot, chain, url -func (_m *SlotHeight) Set(slot types.SlotHeight, chain string, url string) { - _m.Called(slot, chain, url) -} - -// NewSlotHeight creates a new instance of SlotHeight. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewSlotHeight(t interface { - mock.TestingT - Cleanup(func()) -}) *SlotHeight { - mock := &SlotHeight{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/monitoring/metrics/mocks/feed_balances.go b/pkg/monitoring/metrics/mocks/feed_balances.go new file mode 100644 index 000000000..4cbbcc858 --- /dev/null +++ b/pkg/monitoring/metrics/mocks/feed_balances.go @@ -0,0 +1,164 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import ( + metrics "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics" + mock "github.com/stretchr/testify/mock" + + prometheus "github.com/prometheus/client_golang/prometheus" +) + +// FeedBalances is an autogenerated mock type for the FeedBalances type +type FeedBalances struct { + mock.Mock +} + +type FeedBalances_Expecter struct { + mock *mock.Mock +} + +func (_m *FeedBalances) EXPECT() *FeedBalances_Expecter { + return &FeedBalances_Expecter{mock: &_m.Mock} +} + +// Cleanup provides a mock function with given fields: balanceAccountName, feedInput +func (_m *FeedBalances) Cleanup(balanceAccountName string, feedInput metrics.FeedInput) { + _m.Called(balanceAccountName, feedInput) +} + +// FeedBalances_Cleanup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Cleanup' +type FeedBalances_Cleanup_Call struct { + *mock.Call +} + +// Cleanup is a helper method to define mock.On call +// - balanceAccountName string +// - feedInput metrics.FeedInput +func (_e *FeedBalances_Expecter) Cleanup(balanceAccountName interface{}, feedInput interface{}) *FeedBalances_Cleanup_Call { + return &FeedBalances_Cleanup_Call{Call: _e.mock.On("Cleanup", balanceAccountName, feedInput)} +} + +func (_c *FeedBalances_Cleanup_Call) Run(run func(balanceAccountName string, feedInput metrics.FeedInput)) *FeedBalances_Cleanup_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(metrics.FeedInput)) + }) + return _c +} + +func (_c *FeedBalances_Cleanup_Call) Return() *FeedBalances_Cleanup_Call { + _c.Call.Return() + return _c +} + +func (_c *FeedBalances_Cleanup_Call) RunAndReturn(run func(string, metrics.FeedInput)) *FeedBalances_Cleanup_Call { + _c.Call.Return(run) + return _c +} + +// Exists provides a mock function with given fields: balanceAccountName +func (_m *FeedBalances) Exists(balanceAccountName string) (*prometheus.GaugeVec, bool) { + ret := _m.Called(balanceAccountName) + + if len(ret) == 0 { + panic("no return value specified for Exists") + } + + var r0 *prometheus.GaugeVec + var r1 bool + if rf, ok := ret.Get(0).(func(string) (*prometheus.GaugeVec, bool)); ok { + return rf(balanceAccountName) + } + if rf, ok := ret.Get(0).(func(string) *prometheus.GaugeVec); ok { + r0 = rf(balanceAccountName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*prometheus.GaugeVec) + } + } + + if rf, ok := ret.Get(1).(func(string) bool); ok { + r1 = rf(balanceAccountName) + } else { + r1 = ret.Get(1).(bool) + } + + return r0, r1 +} + +// FeedBalances_Exists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Exists' +type FeedBalances_Exists_Call struct { + *mock.Call +} + +// Exists is a helper method to define mock.On call +// - balanceAccountName string +func (_e *FeedBalances_Expecter) Exists(balanceAccountName interface{}) *FeedBalances_Exists_Call { + return &FeedBalances_Exists_Call{Call: _e.mock.On("Exists", balanceAccountName)} +} + +func (_c *FeedBalances_Exists_Call) Run(run func(balanceAccountName string)) *FeedBalances_Exists_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *FeedBalances_Exists_Call) Return(_a0 *prometheus.GaugeVec, _a1 bool) *FeedBalances_Exists_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FeedBalances_Exists_Call) RunAndReturn(run func(string) (*prometheus.GaugeVec, bool)) *FeedBalances_Exists_Call { + _c.Call.Return(run) + return _c +} + +// SetBalance provides a mock function with given fields: balance, balanceAccountName, feedInput +func (_m *FeedBalances) SetBalance(balance uint64, balanceAccountName string, feedInput metrics.FeedInput) { + _m.Called(balance, balanceAccountName, feedInput) +} + +// FeedBalances_SetBalance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetBalance' +type FeedBalances_SetBalance_Call struct { + *mock.Call +} + +// SetBalance is a helper method to define mock.On call +// - balance uint64 +// - balanceAccountName string +// - feedInput metrics.FeedInput +func (_e *FeedBalances_Expecter) SetBalance(balance interface{}, balanceAccountName interface{}, feedInput interface{}) *FeedBalances_SetBalance_Call { + return &FeedBalances_SetBalance_Call{Call: _e.mock.On("SetBalance", balance, balanceAccountName, feedInput)} +} + +func (_c *FeedBalances_SetBalance_Call) Run(run func(balance uint64, balanceAccountName string, feedInput metrics.FeedInput)) *FeedBalances_SetBalance_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(uint64), args[1].(string), args[2].(metrics.FeedInput)) + }) + return _c +} + +func (_c *FeedBalances_SetBalance_Call) Return() *FeedBalances_SetBalance_Call { + _c.Call.Return() + return _c +} + +func (_c *FeedBalances_SetBalance_Call) RunAndReturn(run func(uint64, string, metrics.FeedInput)) *FeedBalances_SetBalance_Call { + _c.Call.Return(run) + return _c +} + +// NewFeedBalances creates a new instance of FeedBalances. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewFeedBalances(t interface { + mock.TestingT + Cleanup(func()) +}) *FeedBalances { + mock := &FeedBalances{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/monitoring/metrics/mocks/network_fees.go b/pkg/monitoring/metrics/mocks/network_fees.go new file mode 100644 index 000000000..1257f3603 --- /dev/null +++ b/pkg/monitoring/metrics/mocks/network_fees.go @@ -0,0 +1,101 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import ( + metrics "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics" + mock "github.com/stretchr/testify/mock" +) + +// NetworkFees is an autogenerated mock type for the NetworkFees type +type NetworkFees struct { + mock.Mock +} + +type NetworkFees_Expecter struct { + mock *mock.Mock +} + +func (_m *NetworkFees) EXPECT() *NetworkFees_Expecter { + return &NetworkFees_Expecter{mock: &_m.Mock} +} + +// Cleanup provides a mock function with given fields: +func (_m *NetworkFees) Cleanup() { + _m.Called() +} + +// NetworkFees_Cleanup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Cleanup' +type NetworkFees_Cleanup_Call struct { + *mock.Call +} + +// Cleanup is a helper method to define mock.On call +func (_e *NetworkFees_Expecter) Cleanup() *NetworkFees_Cleanup_Call { + return &NetworkFees_Cleanup_Call{Call: _e.mock.On("Cleanup")} +} + +func (_c *NetworkFees_Cleanup_Call) Run(run func()) *NetworkFees_Cleanup_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NetworkFees_Cleanup_Call) Return() *NetworkFees_Cleanup_Call { + _c.Call.Return() + return _c +} + +func (_c *NetworkFees_Cleanup_Call) RunAndReturn(run func()) *NetworkFees_Cleanup_Call { + _c.Call.Return(run) + return _c +} + +// Set provides a mock function with given fields: slot, chain +func (_m *NetworkFees) Set(slot metrics.NetworkFeesInput, chain string) { + _m.Called(slot, chain) +} + +// NetworkFees_Set_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Set' +type NetworkFees_Set_Call struct { + *mock.Call +} + +// Set is a helper method to define mock.On call +// - slot metrics.NetworkFeesInput +// - chain string +func (_e *NetworkFees_Expecter) Set(slot interface{}, chain interface{}) *NetworkFees_Set_Call { + return &NetworkFees_Set_Call{Call: _e.mock.On("Set", slot, chain)} +} + +func (_c *NetworkFees_Set_Call) Run(run func(slot metrics.NetworkFeesInput, chain string)) *NetworkFees_Set_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(metrics.NetworkFeesInput), args[1].(string)) + }) + return _c +} + +func (_c *NetworkFees_Set_Call) Return() *NetworkFees_Set_Call { + _c.Call.Return() + return _c +} + +func (_c *NetworkFees_Set_Call) RunAndReturn(run func(metrics.NetworkFeesInput, string)) *NetworkFees_Set_Call { + _c.Call.Return(run) + return _c +} + +// NewNetworkFees creates a new instance of NetworkFees. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewNetworkFees(t interface { + mock.TestingT + Cleanup(func()) +}) *NetworkFees { + mock := &NetworkFees{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/monitoring/metrics/mocks/node_balances.go b/pkg/monitoring/metrics/mocks/node_balances.go new file mode 100644 index 000000000..643a6ca48 --- /dev/null +++ b/pkg/monitoring/metrics/mocks/node_balances.go @@ -0,0 +1,101 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// NodeBalances is an autogenerated mock type for the NodeBalances type +type NodeBalances struct { + mock.Mock +} + +type NodeBalances_Expecter struct { + mock *mock.Mock +} + +func (_m *NodeBalances) EXPECT() *NodeBalances_Expecter { + return &NodeBalances_Expecter{mock: &_m.Mock} +} + +// Cleanup provides a mock function with given fields: address, operator +func (_m *NodeBalances) Cleanup(address string, operator string) { + _m.Called(address, operator) +} + +// NodeBalances_Cleanup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Cleanup' +type NodeBalances_Cleanup_Call struct { + *mock.Call +} + +// Cleanup is a helper method to define mock.On call +// - address string +// - operator string +func (_e *NodeBalances_Expecter) Cleanup(address interface{}, operator interface{}) *NodeBalances_Cleanup_Call { + return &NodeBalances_Cleanup_Call{Call: _e.mock.On("Cleanup", address, operator)} +} + +func (_c *NodeBalances_Cleanup_Call) Run(run func(address string, operator string)) *NodeBalances_Cleanup_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *NodeBalances_Cleanup_Call) Return() *NodeBalances_Cleanup_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeBalances_Cleanup_Call) RunAndReturn(run func(string, string)) *NodeBalances_Cleanup_Call { + _c.Call.Return(run) + return _c +} + +// SetBalance provides a mock function with given fields: balance, address, operator +func (_m *NodeBalances) SetBalance(balance uint64, address string, operator string) { + _m.Called(balance, address, operator) +} + +// NodeBalances_SetBalance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetBalance' +type NodeBalances_SetBalance_Call struct { + *mock.Call +} + +// SetBalance is a helper method to define mock.On call +// - balance uint64 +// - address string +// - operator string +func (_e *NodeBalances_Expecter) SetBalance(balance interface{}, address interface{}, operator interface{}) *NodeBalances_SetBalance_Call { + return &NodeBalances_SetBalance_Call{Call: _e.mock.On("SetBalance", balance, address, operator)} +} + +func (_c *NodeBalances_SetBalance_Call) Run(run func(balance uint64, address string, operator string)) *NodeBalances_SetBalance_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(uint64), args[1].(string), args[2].(string)) + }) + return _c +} + +func (_c *NodeBalances_SetBalance_Call) Return() *NodeBalances_SetBalance_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeBalances_SetBalance_Call) RunAndReturn(run func(uint64, string, string)) *NodeBalances_SetBalance_Call { + _c.Call.Return(run) + return _c +} + +// NewNodeBalances creates a new instance of NodeBalances. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewNodeBalances(t interface { + mock.TestingT + Cleanup(func()) +}) *NodeBalances { + mock := &NodeBalances{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/monitoring/metrics/mocks/node_success.go b/pkg/monitoring/metrics/mocks/node_success.go new file mode 100644 index 000000000..e36aeb501 --- /dev/null +++ b/pkg/monitoring/metrics/mocks/node_success.go @@ -0,0 +1,102 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import ( + metrics "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics" + mock "github.com/stretchr/testify/mock" +) + +// NodeSuccess is an autogenerated mock type for the NodeSuccess type +type NodeSuccess struct { + mock.Mock +} + +type NodeSuccess_Expecter struct { + mock *mock.Mock +} + +func (_m *NodeSuccess) EXPECT() *NodeSuccess_Expecter { + return &NodeSuccess_Expecter{mock: &_m.Mock} +} + +// Add provides a mock function with given fields: count, i +func (_m *NodeSuccess) Add(count int, i metrics.NodeFeedInput) { + _m.Called(count, i) +} + +// NodeSuccess_Add_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Add' +type NodeSuccess_Add_Call struct { + *mock.Call +} + +// Add is a helper method to define mock.On call +// - count int +// - i metrics.NodeFeedInput +func (_e *NodeSuccess_Expecter) Add(count interface{}, i interface{}) *NodeSuccess_Add_Call { + return &NodeSuccess_Add_Call{Call: _e.mock.On("Add", count, i)} +} + +func (_c *NodeSuccess_Add_Call) Run(run func(count int, i metrics.NodeFeedInput)) *NodeSuccess_Add_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int), args[1].(metrics.NodeFeedInput)) + }) + return _c +} + +func (_c *NodeSuccess_Add_Call) Return() *NodeSuccess_Add_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeSuccess_Add_Call) RunAndReturn(run func(int, metrics.NodeFeedInput)) *NodeSuccess_Add_Call { + _c.Call.Return(run) + return _c +} + +// Cleanup provides a mock function with given fields: i +func (_m *NodeSuccess) Cleanup(i metrics.NodeFeedInput) { + _m.Called(i) +} + +// NodeSuccess_Cleanup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Cleanup' +type NodeSuccess_Cleanup_Call struct { + *mock.Call +} + +// Cleanup is a helper method to define mock.On call +// - i metrics.NodeFeedInput +func (_e *NodeSuccess_Expecter) Cleanup(i interface{}) *NodeSuccess_Cleanup_Call { + return &NodeSuccess_Cleanup_Call{Call: _e.mock.On("Cleanup", i)} +} + +func (_c *NodeSuccess_Cleanup_Call) Run(run func(i metrics.NodeFeedInput)) *NodeSuccess_Cleanup_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(metrics.NodeFeedInput)) + }) + return _c +} + +func (_c *NodeSuccess_Cleanup_Call) Return() *NodeSuccess_Cleanup_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeSuccess_Cleanup_Call) RunAndReturn(run func(metrics.NodeFeedInput)) *NodeSuccess_Cleanup_Call { + _c.Call.Return(run) + return _c +} + +// NewNodeSuccess creates a new instance of NodeSuccess. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewNodeSuccess(t interface { + mock.TestingT + Cleanup(func()) +}) *NodeSuccess { + mock := &NodeSuccess{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/monitoring/metrics/mocks/report_observations.go b/pkg/monitoring/metrics/mocks/report_observations.go new file mode 100644 index 000000000..78136a27a --- /dev/null +++ b/pkg/monitoring/metrics/mocks/report_observations.go @@ -0,0 +1,102 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import ( + metrics "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/metrics" + mock "github.com/stretchr/testify/mock" +) + +// ReportObservations is an autogenerated mock type for the ReportObservations type +type ReportObservations struct { + mock.Mock +} + +type ReportObservations_Expecter struct { + mock *mock.Mock +} + +func (_m *ReportObservations) EXPECT() *ReportObservations_Expecter { + return &ReportObservations_Expecter{mock: &_m.Mock} +} + +// Cleanup provides a mock function with given fields: feedInput +func (_m *ReportObservations) Cleanup(feedInput metrics.FeedInput) { + _m.Called(feedInput) +} + +// ReportObservations_Cleanup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Cleanup' +type ReportObservations_Cleanup_Call struct { + *mock.Call +} + +// Cleanup is a helper method to define mock.On call +// - feedInput metrics.FeedInput +func (_e *ReportObservations_Expecter) Cleanup(feedInput interface{}) *ReportObservations_Cleanup_Call { + return &ReportObservations_Cleanup_Call{Call: _e.mock.On("Cleanup", feedInput)} +} + +func (_c *ReportObservations_Cleanup_Call) Run(run func(feedInput metrics.FeedInput)) *ReportObservations_Cleanup_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(metrics.FeedInput)) + }) + return _c +} + +func (_c *ReportObservations_Cleanup_Call) Return() *ReportObservations_Cleanup_Call { + _c.Call.Return() + return _c +} + +func (_c *ReportObservations_Cleanup_Call) RunAndReturn(run func(metrics.FeedInput)) *ReportObservations_Cleanup_Call { + _c.Call.Return(run) + return _c +} + +// SetCount provides a mock function with given fields: count, feedInput +func (_m *ReportObservations) SetCount(count uint8, feedInput metrics.FeedInput) { + _m.Called(count, feedInput) +} + +// ReportObservations_SetCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetCount' +type ReportObservations_SetCount_Call struct { + *mock.Call +} + +// SetCount is a helper method to define mock.On call +// - count uint8 +// - feedInput metrics.FeedInput +func (_e *ReportObservations_Expecter) SetCount(count interface{}, feedInput interface{}) *ReportObservations_SetCount_Call { + return &ReportObservations_SetCount_Call{Call: _e.mock.On("SetCount", count, feedInput)} +} + +func (_c *ReportObservations_SetCount_Call) Run(run func(count uint8, feedInput metrics.FeedInput)) *ReportObservations_SetCount_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(uint8), args[1].(metrics.FeedInput)) + }) + return _c +} + +func (_c *ReportObservations_SetCount_Call) Return() *ReportObservations_SetCount_Call { + _c.Call.Return() + return _c +} + +func (_c *ReportObservations_SetCount_Call) RunAndReturn(run func(uint8, metrics.FeedInput)) *ReportObservations_SetCount_Call { + _c.Call.Return(run) + return _c +} + +// NewReportObservations creates a new instance of ReportObservations. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewReportObservations(t interface { + mock.TestingT + Cleanup(func()) +}) *ReportObservations { + mock := &ReportObservations{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/monitoring/metrics/mocks/slot_height.go b/pkg/monitoring/metrics/mocks/slot_height.go new file mode 100644 index 000000000..990caea39 --- /dev/null +++ b/pkg/monitoring/metrics/mocks/slot_height.go @@ -0,0 +1,102 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import ( + types "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types" + mock "github.com/stretchr/testify/mock" +) + +// SlotHeight is an autogenerated mock type for the SlotHeight type +type SlotHeight struct { + mock.Mock +} + +type SlotHeight_Expecter struct { + mock *mock.Mock +} + +func (_m *SlotHeight) EXPECT() *SlotHeight_Expecter { + return &SlotHeight_Expecter{mock: &_m.Mock} +} + +// Cleanup provides a mock function with given fields: +func (_m *SlotHeight) Cleanup() { + _m.Called() +} + +// SlotHeight_Cleanup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Cleanup' +type SlotHeight_Cleanup_Call struct { + *mock.Call +} + +// Cleanup is a helper method to define mock.On call +func (_e *SlotHeight_Expecter) Cleanup() *SlotHeight_Cleanup_Call { + return &SlotHeight_Cleanup_Call{Call: _e.mock.On("Cleanup")} +} + +func (_c *SlotHeight_Cleanup_Call) Run(run func()) *SlotHeight_Cleanup_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *SlotHeight_Cleanup_Call) Return() *SlotHeight_Cleanup_Call { + _c.Call.Return() + return _c +} + +func (_c *SlotHeight_Cleanup_Call) RunAndReturn(run func()) *SlotHeight_Cleanup_Call { + _c.Call.Return(run) + return _c +} + +// Set provides a mock function with given fields: slot, chain, url +func (_m *SlotHeight) Set(slot types.SlotHeight, chain string, url string) { + _m.Called(slot, chain, url) +} + +// SlotHeight_Set_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Set' +type SlotHeight_Set_Call struct { + *mock.Call +} + +// Set is a helper method to define mock.On call +// - slot types.SlotHeight +// - chain string +// - url string +func (_e *SlotHeight_Expecter) Set(slot interface{}, chain interface{}, url interface{}) *SlotHeight_Set_Call { + return &SlotHeight_Set_Call{Call: _e.mock.On("Set", slot, chain, url)} +} + +func (_c *SlotHeight_Set_Call) Run(run func(slot types.SlotHeight, chain string, url string)) *SlotHeight_Set_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.SlotHeight), args[1].(string), args[2].(string)) + }) + return _c +} + +func (_c *SlotHeight_Set_Call) Return() *SlotHeight_Set_Call { + _c.Call.Return() + return _c +} + +func (_c *SlotHeight_Set_Call) RunAndReturn(run func(types.SlotHeight, string, string)) *SlotHeight_Set_Call { + _c.Call.Return(run) + return _c +} + +// NewSlotHeight creates a new instance of SlotHeight. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewSlotHeight(t interface { + mock.TestingT + Cleanup(func()) +}) *SlotHeight { + mock := &SlotHeight{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/monitoring/metrics/networkfees.go b/pkg/monitoring/metrics/networkfees.go index 9700529e3..be5f93b19 100644 --- a/pkg/monitoring/metrics/networkfees.go +++ b/pkg/monitoring/metrics/networkfees.go @@ -7,8 +7,6 @@ import ( "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types" ) -//go:generate mockery --name NetworkFees --output ./mocks/ - type NetworkFees interface { Set(slot NetworkFeesInput, chain string) Cleanup() diff --git a/pkg/monitoring/metrics/nodebalances.go b/pkg/monitoring/metrics/nodebalances.go index 9e14fa19d..109c8decd 100644 --- a/pkg/monitoring/metrics/nodebalances.go +++ b/pkg/monitoring/metrics/nodebalances.go @@ -8,8 +8,6 @@ import ( "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types" ) -//go:generate mockery --name NodeBalances --output ./mocks/ - type NodeBalances interface { SetBalance(balance uint64, address, operator string) Cleanup(address, operator string) diff --git a/pkg/monitoring/metrics/nodesuccess.go b/pkg/monitoring/metrics/nodesuccess.go index 73cc00d94..87511284b 100644 --- a/pkg/monitoring/metrics/nodesuccess.go +++ b/pkg/monitoring/metrics/nodesuccess.go @@ -6,8 +6,6 @@ import ( "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types" ) -//go:generate mockery --name NodeSuccess --output ./mocks/ - type NodeSuccess interface { Add(count int, i NodeFeedInput) Cleanup(i NodeFeedInput) diff --git a/pkg/monitoring/metrics/reportobservations.go b/pkg/monitoring/metrics/reportobservations.go index f790a4319..7fe037d03 100644 --- a/pkg/monitoring/metrics/reportobservations.go +++ b/pkg/monitoring/metrics/reportobservations.go @@ -6,8 +6,6 @@ import ( "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types" ) -//go:generate mockery --name ReportObservations --output ./mocks/ - type ReportObservations interface { SetCount(count uint8, feedInput FeedInput) Cleanup(feedInput FeedInput) diff --git a/pkg/monitoring/metrics/slotheight.go b/pkg/monitoring/metrics/slotheight.go index 2c4c5caf5..3ccfa2111 100644 --- a/pkg/monitoring/metrics/slotheight.go +++ b/pkg/monitoring/metrics/slotheight.go @@ -7,8 +7,6 @@ import ( "github.com/smartcontractkit/chainlink-solana/pkg/monitoring/types" ) -//go:generate mockery --name SlotHeight --output ./mocks/ - type SlotHeight interface { Set(slot types.SlotHeight, chain, url string) Cleanup() diff --git a/pkg/monitoring/mocks/ChainReader.go b/pkg/monitoring/mocks/ChainReader.go deleted file mode 100644 index 30b714305..000000000 --- a/pkg/monitoring/mocks/ChainReader.go +++ /dev/null @@ -1,282 +0,0 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - mock "github.com/stretchr/testify/mock" - - pkgsolana "github.com/smartcontractkit/chainlink-solana/pkg/solana" - - rpc "github.com/gagliardetto/solana-go/rpc" - - solana "github.com/gagliardetto/solana-go" -) - -// ChainReader is an autogenerated mock type for the ChainReader type -type ChainReader struct { - mock.Mock -} - -// GetBalance provides a mock function with given fields: ctx, account, commitment -func (_m *ChainReader) GetBalance(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType) (*rpc.GetBalanceResult, error) { - ret := _m.Called(ctx, account, commitment) - - if len(ret) == 0 { - panic("no return value specified for GetBalance") - } - - var r0 *rpc.GetBalanceResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) (*rpc.GetBalanceResult, error)); ok { - return rf(ctx, account, commitment) - } - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) *rpc.GetBalanceResult); ok { - r0 = rf(ctx, account, commitment) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rpc.GetBalanceResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, rpc.CommitmentType) error); ok { - r1 = rf(ctx, account, commitment) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetLatestBlock provides a mock function with given fields: ctx, commitment -func (_m *ChainReader) GetLatestBlock(ctx context.Context, commitment rpc.CommitmentType) (*rpc.GetBlockResult, error) { - ret := _m.Called(ctx, commitment) - - if len(ret) == 0 { - panic("no return value specified for GetLatestBlock") - } - - var r0 *rpc.GetBlockResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, rpc.CommitmentType) (*rpc.GetBlockResult, error)); ok { - return rf(ctx, commitment) - } - if rf, ok := ret.Get(0).(func(context.Context, rpc.CommitmentType) *rpc.GetBlockResult); ok { - r0 = rf(ctx, commitment) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rpc.GetBlockResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, rpc.CommitmentType) error); ok { - r1 = rf(ctx, commitment) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetLatestTransmission provides a mock function with given fields: ctx, account, commitment -func (_m *ChainReader) GetLatestTransmission(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType) (pkgsolana.Answer, uint64, error) { - ret := _m.Called(ctx, account, commitment) - - if len(ret) == 0 { - panic("no return value specified for GetLatestTransmission") - } - - var r0 pkgsolana.Answer - var r1 uint64 - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) (pkgsolana.Answer, uint64, error)); ok { - return rf(ctx, account, commitment) - } - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) pkgsolana.Answer); ok { - r0 = rf(ctx, account, commitment) - } else { - r0 = ret.Get(0).(pkgsolana.Answer) - } - - if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, rpc.CommitmentType) uint64); ok { - r1 = rf(ctx, account, commitment) - } else { - r1 = ret.Get(1).(uint64) - } - - if rf, ok := ret.Get(2).(func(context.Context, solana.PublicKey, rpc.CommitmentType) error); ok { - r2 = rf(ctx, account, commitment) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - -// GetSignaturesForAddressWithOpts provides a mock function with given fields: ctx, account, opts -func (_m *ChainReader) GetSignaturesForAddressWithOpts(ctx context.Context, account solana.PublicKey, opts *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error) { - ret := _m.Called(ctx, account, opts) - - if len(ret) == 0 { - panic("no return value specified for GetSignaturesForAddressWithOpts") - } - - var r0 []*rpc.TransactionSignature - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error)); ok { - return rf(ctx, account, opts) - } - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) []*rpc.TransactionSignature); ok { - r0 = rf(ctx, account, opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*rpc.TransactionSignature) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) error); ok { - r1 = rf(ctx, account, opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetSlot provides a mock function with given fields: ctx -func (_m *ChainReader) GetSlot(ctx context.Context) (uint64, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for GetSlot") - } - - var r0 uint64 - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) uint64); ok { - r0 = rf(ctx) - } else { - r0 = ret.Get(0).(uint64) - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetState provides a mock function with given fields: ctx, account, commitment -func (_m *ChainReader) GetState(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType) (pkgsolana.State, uint64, error) { - ret := _m.Called(ctx, account, commitment) - - if len(ret) == 0 { - panic("no return value specified for GetState") - } - - var r0 pkgsolana.State - var r1 uint64 - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) (pkgsolana.State, uint64, error)); ok { - return rf(ctx, account, commitment) - } - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) pkgsolana.State); ok { - r0 = rf(ctx, account, commitment) - } else { - r0 = ret.Get(0).(pkgsolana.State) - } - - if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, rpc.CommitmentType) uint64); ok { - r1 = rf(ctx, account, commitment) - } else { - r1 = ret.Get(1).(uint64) - } - - if rf, ok := ret.Get(2).(func(context.Context, solana.PublicKey, rpc.CommitmentType) error); ok { - r2 = rf(ctx, account, commitment) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - -// GetTokenAccountBalance provides a mock function with given fields: ctx, account, commitment -func (_m *ChainReader) GetTokenAccountBalance(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType) (*rpc.GetTokenAccountBalanceResult, error) { - ret := _m.Called(ctx, account, commitment) - - if len(ret) == 0 { - panic("no return value specified for GetTokenAccountBalance") - } - - var r0 *rpc.GetTokenAccountBalanceResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) (*rpc.GetTokenAccountBalanceResult, error)); ok { - return rf(ctx, account, commitment) - } - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) *rpc.GetTokenAccountBalanceResult); ok { - r0 = rf(ctx, account, commitment) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rpc.GetTokenAccountBalanceResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, rpc.CommitmentType) error); ok { - r1 = rf(ctx, account, commitment) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetTransaction provides a mock function with given fields: ctx, txSig, opts -func (_m *ChainReader) GetTransaction(ctx context.Context, txSig solana.Signature, opts *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error) { - ret := _m.Called(ctx, txSig, opts) - - if len(ret) == 0 { - panic("no return value specified for GetTransaction") - } - - var r0 *rpc.GetTransactionResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error)); ok { - return rf(ctx, txSig, opts) - } - if rf, ok := ret.Get(0).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) *rpc.GetTransactionResult); ok { - r0 = rf(ctx, txSig, opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rpc.GetTransactionResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) error); ok { - r1 = rf(ctx, txSig, opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewChainReader creates a new instance of ChainReader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewChainReader(t interface { - mock.TestingT - Cleanup(func()) -}) *ChainReader { - mock := &ChainReader{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/monitoring/mocks/chain_reader.go b/pkg/monitoring/mocks/chain_reader.go new file mode 100644 index 000000000..e6a1e655a --- /dev/null +++ b/pkg/monitoring/mocks/chain_reader.go @@ -0,0 +1,527 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + pkgsolana "github.com/smartcontractkit/chainlink-solana/pkg/solana" + + rpc "github.com/gagliardetto/solana-go/rpc" + + solana "github.com/gagliardetto/solana-go" +) + +// ChainReader is an autogenerated mock type for the ChainReader type +type ChainReader struct { + mock.Mock +} + +type ChainReader_Expecter struct { + mock *mock.Mock +} + +func (_m *ChainReader) EXPECT() *ChainReader_Expecter { + return &ChainReader_Expecter{mock: &_m.Mock} +} + +// GetBalance provides a mock function with given fields: ctx, account, commitment +func (_m *ChainReader) GetBalance(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType) (*rpc.GetBalanceResult, error) { + ret := _m.Called(ctx, account, commitment) + + if len(ret) == 0 { + panic("no return value specified for GetBalance") + } + + var r0 *rpc.GetBalanceResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) (*rpc.GetBalanceResult, error)); ok { + return rf(ctx, account, commitment) + } + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) *rpc.GetBalanceResult); ok { + r0 = rf(ctx, account, commitment) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetBalanceResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, rpc.CommitmentType) error); ok { + r1 = rf(ctx, account, commitment) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ChainReader_GetBalance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBalance' +type ChainReader_GetBalance_Call struct { + *mock.Call +} + +// GetBalance is a helper method to define mock.On call +// - ctx context.Context +// - account solana.PublicKey +// - commitment rpc.CommitmentType +func (_e *ChainReader_Expecter) GetBalance(ctx interface{}, account interface{}, commitment interface{}) *ChainReader_GetBalance_Call { + return &ChainReader_GetBalance_Call{Call: _e.mock.On("GetBalance", ctx, account, commitment)} +} + +func (_c *ChainReader_GetBalance_Call) Run(run func(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType)) *ChainReader_GetBalance_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(solana.PublicKey), args[2].(rpc.CommitmentType)) + }) + return _c +} + +func (_c *ChainReader_GetBalance_Call) Return(out *rpc.GetBalanceResult, err error) *ChainReader_GetBalance_Call { + _c.Call.Return(out, err) + return _c +} + +func (_c *ChainReader_GetBalance_Call) RunAndReturn(run func(context.Context, solana.PublicKey, rpc.CommitmentType) (*rpc.GetBalanceResult, error)) *ChainReader_GetBalance_Call { + _c.Call.Return(run) + return _c +} + +// GetLatestBlock provides a mock function with given fields: ctx, commitment +func (_m *ChainReader) GetLatestBlock(ctx context.Context, commitment rpc.CommitmentType) (*rpc.GetBlockResult, error) { + ret := _m.Called(ctx, commitment) + + if len(ret) == 0 { + panic("no return value specified for GetLatestBlock") + } + + var r0 *rpc.GetBlockResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, rpc.CommitmentType) (*rpc.GetBlockResult, error)); ok { + return rf(ctx, commitment) + } + if rf, ok := ret.Get(0).(func(context.Context, rpc.CommitmentType) *rpc.GetBlockResult); ok { + r0 = rf(ctx, commitment) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetBlockResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, rpc.CommitmentType) error); ok { + r1 = rf(ctx, commitment) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ChainReader_GetLatestBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestBlock' +type ChainReader_GetLatestBlock_Call struct { + *mock.Call +} + +// GetLatestBlock is a helper method to define mock.On call +// - ctx context.Context +// - commitment rpc.CommitmentType +func (_e *ChainReader_Expecter) GetLatestBlock(ctx interface{}, commitment interface{}) *ChainReader_GetLatestBlock_Call { + return &ChainReader_GetLatestBlock_Call{Call: _e.mock.On("GetLatestBlock", ctx, commitment)} +} + +func (_c *ChainReader_GetLatestBlock_Call) Run(run func(ctx context.Context, commitment rpc.CommitmentType)) *ChainReader_GetLatestBlock_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(rpc.CommitmentType)) + }) + return _c +} + +func (_c *ChainReader_GetLatestBlock_Call) Return(_a0 *rpc.GetBlockResult, _a1 error) *ChainReader_GetLatestBlock_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ChainReader_GetLatestBlock_Call) RunAndReturn(run func(context.Context, rpc.CommitmentType) (*rpc.GetBlockResult, error)) *ChainReader_GetLatestBlock_Call { + _c.Call.Return(run) + return _c +} + +// GetLatestTransmission provides a mock function with given fields: ctx, account, commitment +func (_m *ChainReader) GetLatestTransmission(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType) (pkgsolana.Answer, uint64, error) { + ret := _m.Called(ctx, account, commitment) + + if len(ret) == 0 { + panic("no return value specified for GetLatestTransmission") + } + + var r0 pkgsolana.Answer + var r1 uint64 + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) (pkgsolana.Answer, uint64, error)); ok { + return rf(ctx, account, commitment) + } + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) pkgsolana.Answer); ok { + r0 = rf(ctx, account, commitment) + } else { + r0 = ret.Get(0).(pkgsolana.Answer) + } + + if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, rpc.CommitmentType) uint64); ok { + r1 = rf(ctx, account, commitment) + } else { + r1 = ret.Get(1).(uint64) + } + + if rf, ok := ret.Get(2).(func(context.Context, solana.PublicKey, rpc.CommitmentType) error); ok { + r2 = rf(ctx, account, commitment) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// ChainReader_GetLatestTransmission_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestTransmission' +type ChainReader_GetLatestTransmission_Call struct { + *mock.Call +} + +// GetLatestTransmission is a helper method to define mock.On call +// - ctx context.Context +// - account solana.PublicKey +// - commitment rpc.CommitmentType +func (_e *ChainReader_Expecter) GetLatestTransmission(ctx interface{}, account interface{}, commitment interface{}) *ChainReader_GetLatestTransmission_Call { + return &ChainReader_GetLatestTransmission_Call{Call: _e.mock.On("GetLatestTransmission", ctx, account, commitment)} +} + +func (_c *ChainReader_GetLatestTransmission_Call) Run(run func(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType)) *ChainReader_GetLatestTransmission_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(solana.PublicKey), args[2].(rpc.CommitmentType)) + }) + return _c +} + +func (_c *ChainReader_GetLatestTransmission_Call) Return(answer pkgsolana.Answer, blockHeight uint64, err error) *ChainReader_GetLatestTransmission_Call { + _c.Call.Return(answer, blockHeight, err) + return _c +} + +func (_c *ChainReader_GetLatestTransmission_Call) RunAndReturn(run func(context.Context, solana.PublicKey, rpc.CommitmentType) (pkgsolana.Answer, uint64, error)) *ChainReader_GetLatestTransmission_Call { + _c.Call.Return(run) + return _c +} + +// GetSignaturesForAddressWithOpts provides a mock function with given fields: ctx, account, opts +func (_m *ChainReader) GetSignaturesForAddressWithOpts(ctx context.Context, account solana.PublicKey, opts *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error) { + ret := _m.Called(ctx, account, opts) + + if len(ret) == 0 { + panic("no return value specified for GetSignaturesForAddressWithOpts") + } + + var r0 []*rpc.TransactionSignature + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error)); ok { + return rf(ctx, account, opts) + } + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) []*rpc.TransactionSignature); ok { + r0 = rf(ctx, account, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*rpc.TransactionSignature) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) error); ok { + r1 = rf(ctx, account, opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ChainReader_GetSignaturesForAddressWithOpts_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSignaturesForAddressWithOpts' +type ChainReader_GetSignaturesForAddressWithOpts_Call struct { + *mock.Call +} + +// GetSignaturesForAddressWithOpts is a helper method to define mock.On call +// - ctx context.Context +// - account solana.PublicKey +// - opts *rpc.GetSignaturesForAddressOpts +func (_e *ChainReader_Expecter) GetSignaturesForAddressWithOpts(ctx interface{}, account interface{}, opts interface{}) *ChainReader_GetSignaturesForAddressWithOpts_Call { + return &ChainReader_GetSignaturesForAddressWithOpts_Call{Call: _e.mock.On("GetSignaturesForAddressWithOpts", ctx, account, opts)} +} + +func (_c *ChainReader_GetSignaturesForAddressWithOpts_Call) Run(run func(ctx context.Context, account solana.PublicKey, opts *rpc.GetSignaturesForAddressOpts)) *ChainReader_GetSignaturesForAddressWithOpts_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(solana.PublicKey), args[2].(*rpc.GetSignaturesForAddressOpts)) + }) + return _c +} + +func (_c *ChainReader_GetSignaturesForAddressWithOpts_Call) Return(out []*rpc.TransactionSignature, err error) *ChainReader_GetSignaturesForAddressWithOpts_Call { + _c.Call.Return(out, err) + return _c +} + +func (_c *ChainReader_GetSignaturesForAddressWithOpts_Call) RunAndReturn(run func(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error)) *ChainReader_GetSignaturesForAddressWithOpts_Call { + _c.Call.Return(run) + return _c +} + +// GetSlot provides a mock function with given fields: ctx +func (_m *ChainReader) GetSlot(ctx context.Context) (uint64, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetSlot") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) uint64); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ChainReader_GetSlot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlot' +type ChainReader_GetSlot_Call struct { + *mock.Call +} + +// GetSlot is a helper method to define mock.On call +// - ctx context.Context +func (_e *ChainReader_Expecter) GetSlot(ctx interface{}) *ChainReader_GetSlot_Call { + return &ChainReader_GetSlot_Call{Call: _e.mock.On("GetSlot", ctx)} +} + +func (_c *ChainReader_GetSlot_Call) Run(run func(ctx context.Context)) *ChainReader_GetSlot_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *ChainReader_GetSlot_Call) Return(slot uint64, err error) *ChainReader_GetSlot_Call { + _c.Call.Return(slot, err) + return _c +} + +func (_c *ChainReader_GetSlot_Call) RunAndReturn(run func(context.Context) (uint64, error)) *ChainReader_GetSlot_Call { + _c.Call.Return(run) + return _c +} + +// GetState provides a mock function with given fields: ctx, account, commitment +func (_m *ChainReader) GetState(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType) (pkgsolana.State, uint64, error) { + ret := _m.Called(ctx, account, commitment) + + if len(ret) == 0 { + panic("no return value specified for GetState") + } + + var r0 pkgsolana.State + var r1 uint64 + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) (pkgsolana.State, uint64, error)); ok { + return rf(ctx, account, commitment) + } + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) pkgsolana.State); ok { + r0 = rf(ctx, account, commitment) + } else { + r0 = ret.Get(0).(pkgsolana.State) + } + + if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, rpc.CommitmentType) uint64); ok { + r1 = rf(ctx, account, commitment) + } else { + r1 = ret.Get(1).(uint64) + } + + if rf, ok := ret.Get(2).(func(context.Context, solana.PublicKey, rpc.CommitmentType) error); ok { + r2 = rf(ctx, account, commitment) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// ChainReader_GetState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetState' +type ChainReader_GetState_Call struct { + *mock.Call +} + +// GetState is a helper method to define mock.On call +// - ctx context.Context +// - account solana.PublicKey +// - commitment rpc.CommitmentType +func (_e *ChainReader_Expecter) GetState(ctx interface{}, account interface{}, commitment interface{}) *ChainReader_GetState_Call { + return &ChainReader_GetState_Call{Call: _e.mock.On("GetState", ctx, account, commitment)} +} + +func (_c *ChainReader_GetState_Call) Run(run func(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType)) *ChainReader_GetState_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(solana.PublicKey), args[2].(rpc.CommitmentType)) + }) + return _c +} + +func (_c *ChainReader_GetState_Call) Return(state pkgsolana.State, blockHeight uint64, err error) *ChainReader_GetState_Call { + _c.Call.Return(state, blockHeight, err) + return _c +} + +func (_c *ChainReader_GetState_Call) RunAndReturn(run func(context.Context, solana.PublicKey, rpc.CommitmentType) (pkgsolana.State, uint64, error)) *ChainReader_GetState_Call { + _c.Call.Return(run) + return _c +} + +// GetTokenAccountBalance provides a mock function with given fields: ctx, account, commitment +func (_m *ChainReader) GetTokenAccountBalance(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType) (*rpc.GetTokenAccountBalanceResult, error) { + ret := _m.Called(ctx, account, commitment) + + if len(ret) == 0 { + panic("no return value specified for GetTokenAccountBalance") + } + + var r0 *rpc.GetTokenAccountBalanceResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) (*rpc.GetTokenAccountBalanceResult, error)); ok { + return rf(ctx, account, commitment) + } + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, rpc.CommitmentType) *rpc.GetTokenAccountBalanceResult); ok { + r0 = rf(ctx, account, commitment) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetTokenAccountBalanceResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, rpc.CommitmentType) error); ok { + r1 = rf(ctx, account, commitment) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ChainReader_GetTokenAccountBalance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenAccountBalance' +type ChainReader_GetTokenAccountBalance_Call struct { + *mock.Call +} + +// GetTokenAccountBalance is a helper method to define mock.On call +// - ctx context.Context +// - account solana.PublicKey +// - commitment rpc.CommitmentType +func (_e *ChainReader_Expecter) GetTokenAccountBalance(ctx interface{}, account interface{}, commitment interface{}) *ChainReader_GetTokenAccountBalance_Call { + return &ChainReader_GetTokenAccountBalance_Call{Call: _e.mock.On("GetTokenAccountBalance", ctx, account, commitment)} +} + +func (_c *ChainReader_GetTokenAccountBalance_Call) Run(run func(ctx context.Context, account solana.PublicKey, commitment rpc.CommitmentType)) *ChainReader_GetTokenAccountBalance_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(solana.PublicKey), args[2].(rpc.CommitmentType)) + }) + return _c +} + +func (_c *ChainReader_GetTokenAccountBalance_Call) Return(out *rpc.GetTokenAccountBalanceResult, err error) *ChainReader_GetTokenAccountBalance_Call { + _c.Call.Return(out, err) + return _c +} + +func (_c *ChainReader_GetTokenAccountBalance_Call) RunAndReturn(run func(context.Context, solana.PublicKey, rpc.CommitmentType) (*rpc.GetTokenAccountBalanceResult, error)) *ChainReader_GetTokenAccountBalance_Call { + _c.Call.Return(run) + return _c +} + +// GetTransaction provides a mock function with given fields: ctx, txSig, opts +func (_m *ChainReader) GetTransaction(ctx context.Context, txSig solana.Signature, opts *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error) { + ret := _m.Called(ctx, txSig, opts) + + if len(ret) == 0 { + panic("no return value specified for GetTransaction") + } + + var r0 *rpc.GetTransactionResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error)); ok { + return rf(ctx, txSig, opts) + } + if rf, ok := ret.Get(0).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) *rpc.GetTransactionResult); ok { + r0 = rf(ctx, txSig, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetTransactionResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) error); ok { + r1 = rf(ctx, txSig, opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ChainReader_GetTransaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTransaction' +type ChainReader_GetTransaction_Call struct { + *mock.Call +} + +// GetTransaction is a helper method to define mock.On call +// - ctx context.Context +// - txSig solana.Signature +// - opts *rpc.GetTransactionOpts +func (_e *ChainReader_Expecter) GetTransaction(ctx interface{}, txSig interface{}, opts interface{}) *ChainReader_GetTransaction_Call { + return &ChainReader_GetTransaction_Call{Call: _e.mock.On("GetTransaction", ctx, txSig, opts)} +} + +func (_c *ChainReader_GetTransaction_Call) Run(run func(ctx context.Context, txSig solana.Signature, opts *rpc.GetTransactionOpts)) *ChainReader_GetTransaction_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(solana.Signature), args[2].(*rpc.GetTransactionOpts)) + }) + return _c +} + +func (_c *ChainReader_GetTransaction_Call) Return(out *rpc.GetTransactionResult, err error) *ChainReader_GetTransaction_Call { + _c.Call.Return(out, err) + return _c +} + +func (_c *ChainReader_GetTransaction_Call) RunAndReturn(run func(context.Context, solana.Signature, *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error)) *ChainReader_GetTransaction_Call { + _c.Call.Return(run) + return _c +} + +// NewChainReader creates a new instance of ChainReader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewChainReader(t interface { + mock.TestingT + Cleanup(func()) +}) *ChainReader { + mock := &ChainReader{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/solana/client/client.go b/pkg/solana/client/client.go index 18c0e4bfe..f9f6715b0 100644 --- a/pkg/solana/client/client.go +++ b/pkg/solana/client/client.go @@ -23,7 +23,6 @@ const ( MainnetGenesisHash = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d" ) -//go:generate mockery --name ReaderWriter --output ./mocks/ type ReaderWriter interface { Writer Reader diff --git a/pkg/solana/client/mocks/ReaderWriter.go b/pkg/solana/client/mocks/ReaderWriter.go deleted file mode 100644 index f4d514459..000000000 --- a/pkg/solana/client/mocks/ReaderWriter.go +++ /dev/null @@ -1,384 +0,0 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - rpc "github.com/gagliardetto/solana-go/rpc" - multinode "github.com/smartcontractkit/chainlink-solana/pkg/solana/client/multinode" - mock "github.com/stretchr/testify/mock" - - solana "github.com/gagliardetto/solana-go" -) - -// ReaderWriter is an autogenerated mock type for the ReaderWriter type -type ReaderWriter struct { - mock.Mock -} - -// Balance provides a mock function with given fields: ctx, addr -func (_m *ReaderWriter) Balance(ctx context.Context, addr solana.PublicKey) (uint64, error) { - ret := _m.Called(ctx, addr) - - if len(ret) == 0 { - panic("no return value specified for Balance") - } - - var r0 uint64 - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey) (uint64, error)); ok { - return rf(ctx, addr) - } - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey) uint64); ok { - r0 = rf(ctx, addr) - } else { - r0 = ret.Get(0).(uint64) - } - - if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey) error); ok { - r1 = rf(ctx, addr) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ChainID provides a mock function with given fields: ctx -func (_m *ReaderWriter) ChainID(ctx context.Context) (multinode.StringID, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for ChainID") - } - - var r0 multinode.StringID - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (multinode.StringID, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) multinode.StringID); ok { - r0 = rf(ctx) - } else { - r0 = ret.Get(0).(multinode.StringID) - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetAccountInfoWithOpts provides a mock function with given fields: ctx, addr, opts -func (_m *ReaderWriter) GetAccountInfoWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetAccountInfoOpts) (*rpc.GetAccountInfoResult, error) { - ret := _m.Called(ctx, addr, opts) - - if len(ret) == 0 { - panic("no return value specified for GetAccountInfoWithOpts") - } - - var r0 *rpc.GetAccountInfoResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetAccountInfoOpts) (*rpc.GetAccountInfoResult, error)); ok { - return rf(ctx, addr, opts) - } - if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetAccountInfoOpts) *rpc.GetAccountInfoResult); ok { - r0 = rf(ctx, addr, opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rpc.GetAccountInfoResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, *rpc.GetAccountInfoOpts) error); ok { - r1 = rf(ctx, addr, opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetBlock provides a mock function with given fields: ctx, slot -func (_m *ReaderWriter) GetBlock(ctx context.Context, slot uint64) (*rpc.GetBlockResult, error) { - ret := _m.Called(ctx, slot) - - if len(ret) == 0 { - panic("no return value specified for GetBlock") - } - - var r0 *rpc.GetBlockResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uint64) (*rpc.GetBlockResult, error)); ok { - return rf(ctx, slot) - } - if rf, ok := ret.Get(0).(func(context.Context, uint64) *rpc.GetBlockResult); ok { - r0 = rf(ctx, slot) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rpc.GetBlockResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, uint64) error); ok { - r1 = rf(ctx, slot) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetBlocksWithLimit provides a mock function with given fields: ctx, startSlot, limit -func (_m *ReaderWriter) GetBlocksWithLimit(ctx context.Context, startSlot uint64, limit uint64) (*rpc.BlocksResult, error) { - ret := _m.Called(ctx, startSlot, limit) - - if len(ret) == 0 { - panic("no return value specified for GetBlocksWithLimit") - } - - var r0 *rpc.BlocksResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) (*rpc.BlocksResult, error)); ok { - return rf(ctx, startSlot, limit) - } - if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) *rpc.BlocksResult); ok { - r0 = rf(ctx, startSlot, limit) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rpc.BlocksResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64) error); ok { - r1 = rf(ctx, startSlot, limit) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetFeeForMessage provides a mock function with given fields: ctx, msg -func (_m *ReaderWriter) GetFeeForMessage(ctx context.Context, msg string) (uint64, error) { - ret := _m.Called(ctx, msg) - - if len(ret) == 0 { - panic("no return value specified for GetFeeForMessage") - } - - var r0 uint64 - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (uint64, error)); ok { - return rf(ctx, msg) - } - if rf, ok := ret.Get(0).(func(context.Context, string) uint64); ok { - r0 = rf(ctx, msg) - } else { - r0 = ret.Get(0).(uint64) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, msg) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetLatestBlock provides a mock function with given fields: ctx -func (_m *ReaderWriter) GetLatestBlock(ctx context.Context) (*rpc.GetBlockResult, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for GetLatestBlock") - } - - var r0 *rpc.GetBlockResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (*rpc.GetBlockResult, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) *rpc.GetBlockResult); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rpc.GetBlockResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// LatestBlockhash provides a mock function with given fields: ctx -func (_m *ReaderWriter) LatestBlockhash(ctx context.Context) (*rpc.GetLatestBlockhashResult, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for LatestBlockhash") - } - - var r0 *rpc.GetLatestBlockhashResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (*rpc.GetLatestBlockhashResult, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) *rpc.GetLatestBlockhashResult); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rpc.GetLatestBlockhashResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SendTx provides a mock function with given fields: ctx, tx -func (_m *ReaderWriter) SendTx(ctx context.Context, tx *solana.Transaction) (solana.Signature, error) { - ret := _m.Called(ctx, tx) - - if len(ret) == 0 { - panic("no return value specified for SendTx") - } - - var r0 solana.Signature - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *solana.Transaction) (solana.Signature, error)); ok { - return rf(ctx, tx) - } - if rf, ok := ret.Get(0).(func(context.Context, *solana.Transaction) solana.Signature); ok { - r0 = rf(ctx, tx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(solana.Signature) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, *solana.Transaction) error); ok { - r1 = rf(ctx, tx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SignatureStatuses provides a mock function with given fields: ctx, sigs -func (_m *ReaderWriter) SignatureStatuses(ctx context.Context, sigs []solana.Signature) ([]*rpc.SignatureStatusesResult, error) { - ret := _m.Called(ctx, sigs) - - if len(ret) == 0 { - panic("no return value specified for SignatureStatuses") - } - - var r0 []*rpc.SignatureStatusesResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []solana.Signature) ([]*rpc.SignatureStatusesResult, error)); ok { - return rf(ctx, sigs) - } - if rf, ok := ret.Get(0).(func(context.Context, []solana.Signature) []*rpc.SignatureStatusesResult); ok { - r0 = rf(ctx, sigs) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*rpc.SignatureStatusesResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, []solana.Signature) error); ok { - r1 = rf(ctx, sigs) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SimulateTx provides a mock function with given fields: ctx, tx, opts -func (_m *ReaderWriter) SimulateTx(ctx context.Context, tx *solana.Transaction, opts *rpc.SimulateTransactionOpts) (*rpc.SimulateTransactionResult, error) { - ret := _m.Called(ctx, tx, opts) - - if len(ret) == 0 { - panic("no return value specified for SimulateTx") - } - - var r0 *rpc.SimulateTransactionResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *solana.Transaction, *rpc.SimulateTransactionOpts) (*rpc.SimulateTransactionResult, error)); ok { - return rf(ctx, tx, opts) - } - if rf, ok := ret.Get(0).(func(context.Context, *solana.Transaction, *rpc.SimulateTransactionOpts) *rpc.SimulateTransactionResult); ok { - r0 = rf(ctx, tx, opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rpc.SimulateTransactionResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, *solana.Transaction, *rpc.SimulateTransactionOpts) error); ok { - r1 = rf(ctx, tx, opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SlotHeight provides a mock function with given fields: ctx -func (_m *ReaderWriter) SlotHeight(ctx context.Context) (uint64, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for SlotHeight") - } - - var r0 uint64 - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) uint64); ok { - r0 = rf(ctx) - } else { - r0 = ret.Get(0).(uint64) - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewReaderWriter creates a new instance of ReaderWriter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewReaderWriter(t interface { - mock.TestingT - Cleanup(func()) -}) *ReaderWriter { - mock := &ReaderWriter{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/solana/client/mocks/reader_writer.go b/pkg/solana/client/mocks/reader_writer.go new file mode 100644 index 000000000..86285fdf5 --- /dev/null +++ b/pkg/solana/client/mocks/reader_writer.go @@ -0,0 +1,739 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import ( + context "context" + + rpc "github.com/gagliardetto/solana-go/rpc" + multinode "github.com/smartcontractkit/chainlink-solana/pkg/solana/client/multinode" + mock "github.com/stretchr/testify/mock" + + solana "github.com/gagliardetto/solana-go" +) + +// ReaderWriter is an autogenerated mock type for the ReaderWriter type +type ReaderWriter struct { + mock.Mock +} + +type ReaderWriter_Expecter struct { + mock *mock.Mock +} + +func (_m *ReaderWriter) EXPECT() *ReaderWriter_Expecter { + return &ReaderWriter_Expecter{mock: &_m.Mock} +} + +// Balance provides a mock function with given fields: ctx, addr +func (_m *ReaderWriter) Balance(ctx context.Context, addr solana.PublicKey) (uint64, error) { + ret := _m.Called(ctx, addr) + + if len(ret) == 0 { + panic("no return value specified for Balance") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey) (uint64, error)); ok { + return rf(ctx, addr) + } + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey) uint64); ok { + r0 = rf(ctx, addr) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey) error); ok { + r1 = rf(ctx, addr) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_Balance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Balance' +type ReaderWriter_Balance_Call struct { + *mock.Call +} + +// Balance is a helper method to define mock.On call +// - ctx context.Context +// - addr solana.PublicKey +func (_e *ReaderWriter_Expecter) Balance(ctx interface{}, addr interface{}) *ReaderWriter_Balance_Call { + return &ReaderWriter_Balance_Call{Call: _e.mock.On("Balance", ctx, addr)} +} + +func (_c *ReaderWriter_Balance_Call) Run(run func(ctx context.Context, addr solana.PublicKey)) *ReaderWriter_Balance_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(solana.PublicKey)) + }) + return _c +} + +func (_c *ReaderWriter_Balance_Call) Return(_a0 uint64, _a1 error) *ReaderWriter_Balance_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_Balance_Call) RunAndReturn(run func(context.Context, solana.PublicKey) (uint64, error)) *ReaderWriter_Balance_Call { + _c.Call.Return(run) + return _c +} + +// ChainID provides a mock function with given fields: ctx +func (_m *ReaderWriter) ChainID(ctx context.Context) (multinode.StringID, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + + var r0 multinode.StringID + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (multinode.StringID, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) multinode.StringID); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(multinode.StringID) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_ChainID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ChainID' +type ReaderWriter_ChainID_Call struct { + *mock.Call +} + +// ChainID is a helper method to define mock.On call +// - ctx context.Context +func (_e *ReaderWriter_Expecter) ChainID(ctx interface{}) *ReaderWriter_ChainID_Call { + return &ReaderWriter_ChainID_Call{Call: _e.mock.On("ChainID", ctx)} +} + +func (_c *ReaderWriter_ChainID_Call) Run(run func(ctx context.Context)) *ReaderWriter_ChainID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *ReaderWriter_ChainID_Call) Return(_a0 multinode.StringID, _a1 error) *ReaderWriter_ChainID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_ChainID_Call) RunAndReturn(run func(context.Context) (multinode.StringID, error)) *ReaderWriter_ChainID_Call { + _c.Call.Return(run) + return _c +} + +// GetAccountInfoWithOpts provides a mock function with given fields: ctx, addr, opts +func (_m *ReaderWriter) GetAccountInfoWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetAccountInfoOpts) (*rpc.GetAccountInfoResult, error) { + ret := _m.Called(ctx, addr, opts) + + if len(ret) == 0 { + panic("no return value specified for GetAccountInfoWithOpts") + } + + var r0 *rpc.GetAccountInfoResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetAccountInfoOpts) (*rpc.GetAccountInfoResult, error)); ok { + return rf(ctx, addr, opts) + } + if rf, ok := ret.Get(0).(func(context.Context, solana.PublicKey, *rpc.GetAccountInfoOpts) *rpc.GetAccountInfoResult); ok { + r0 = rf(ctx, addr, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetAccountInfoResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, solana.PublicKey, *rpc.GetAccountInfoOpts) error); ok { + r1 = rf(ctx, addr, opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_GetAccountInfoWithOpts_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAccountInfoWithOpts' +type ReaderWriter_GetAccountInfoWithOpts_Call struct { + *mock.Call +} + +// GetAccountInfoWithOpts is a helper method to define mock.On call +// - ctx context.Context +// - addr solana.PublicKey +// - opts *rpc.GetAccountInfoOpts +func (_e *ReaderWriter_Expecter) GetAccountInfoWithOpts(ctx interface{}, addr interface{}, opts interface{}) *ReaderWriter_GetAccountInfoWithOpts_Call { + return &ReaderWriter_GetAccountInfoWithOpts_Call{Call: _e.mock.On("GetAccountInfoWithOpts", ctx, addr, opts)} +} + +func (_c *ReaderWriter_GetAccountInfoWithOpts_Call) Run(run func(ctx context.Context, addr solana.PublicKey, opts *rpc.GetAccountInfoOpts)) *ReaderWriter_GetAccountInfoWithOpts_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(solana.PublicKey), args[2].(*rpc.GetAccountInfoOpts)) + }) + return _c +} + +func (_c *ReaderWriter_GetAccountInfoWithOpts_Call) Return(_a0 *rpc.GetAccountInfoResult, _a1 error) *ReaderWriter_GetAccountInfoWithOpts_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_GetAccountInfoWithOpts_Call) RunAndReturn(run func(context.Context, solana.PublicKey, *rpc.GetAccountInfoOpts) (*rpc.GetAccountInfoResult, error)) *ReaderWriter_GetAccountInfoWithOpts_Call { + _c.Call.Return(run) + return _c +} + +// GetBlock provides a mock function with given fields: ctx, slot +func (_m *ReaderWriter) GetBlock(ctx context.Context, slot uint64) (*rpc.GetBlockResult, error) { + ret := _m.Called(ctx, slot) + + if len(ret) == 0 { + panic("no return value specified for GetBlock") + } + + var r0 *rpc.GetBlockResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64) (*rpc.GetBlockResult, error)); ok { + return rf(ctx, slot) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64) *rpc.GetBlockResult); ok { + r0 = rf(ctx, slot) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetBlockResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64) error); ok { + r1 = rf(ctx, slot) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_GetBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlock' +type ReaderWriter_GetBlock_Call struct { + *mock.Call +} + +// GetBlock is a helper method to define mock.On call +// - ctx context.Context +// - slot uint64 +func (_e *ReaderWriter_Expecter) GetBlock(ctx interface{}, slot interface{}) *ReaderWriter_GetBlock_Call { + return &ReaderWriter_GetBlock_Call{Call: _e.mock.On("GetBlock", ctx, slot)} +} + +func (_c *ReaderWriter_GetBlock_Call) Run(run func(ctx context.Context, slot uint64)) *ReaderWriter_GetBlock_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64)) + }) + return _c +} + +func (_c *ReaderWriter_GetBlock_Call) Return(_a0 *rpc.GetBlockResult, _a1 error) *ReaderWriter_GetBlock_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_GetBlock_Call) RunAndReturn(run func(context.Context, uint64) (*rpc.GetBlockResult, error)) *ReaderWriter_GetBlock_Call { + _c.Call.Return(run) + return _c +} + +// GetBlocksWithLimit provides a mock function with given fields: ctx, startSlot, limit +func (_m *ReaderWriter) GetBlocksWithLimit(ctx context.Context, startSlot uint64, limit uint64) (*rpc.BlocksResult, error) { + ret := _m.Called(ctx, startSlot, limit) + + if len(ret) == 0 { + panic("no return value specified for GetBlocksWithLimit") + } + + var r0 *rpc.BlocksResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) (*rpc.BlocksResult, error)); ok { + return rf(ctx, startSlot, limit) + } + if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) *rpc.BlocksResult); ok { + r0 = rf(ctx, startSlot, limit) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.BlocksResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64) error); ok { + r1 = rf(ctx, startSlot, limit) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_GetBlocksWithLimit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlocksWithLimit' +type ReaderWriter_GetBlocksWithLimit_Call struct { + *mock.Call +} + +// GetBlocksWithLimit is a helper method to define mock.On call +// - ctx context.Context +// - startSlot uint64 +// - limit uint64 +func (_e *ReaderWriter_Expecter) GetBlocksWithLimit(ctx interface{}, startSlot interface{}, limit interface{}) *ReaderWriter_GetBlocksWithLimit_Call { + return &ReaderWriter_GetBlocksWithLimit_Call{Call: _e.mock.On("GetBlocksWithLimit", ctx, startSlot, limit)} +} + +func (_c *ReaderWriter_GetBlocksWithLimit_Call) Run(run func(ctx context.Context, startSlot uint64, limit uint64)) *ReaderWriter_GetBlocksWithLimit_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(uint64)) + }) + return _c +} + +func (_c *ReaderWriter_GetBlocksWithLimit_Call) Return(_a0 *rpc.BlocksResult, _a1 error) *ReaderWriter_GetBlocksWithLimit_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_GetBlocksWithLimit_Call) RunAndReturn(run func(context.Context, uint64, uint64) (*rpc.BlocksResult, error)) *ReaderWriter_GetBlocksWithLimit_Call { + _c.Call.Return(run) + return _c +} + +// GetFeeForMessage provides a mock function with given fields: ctx, msg +func (_m *ReaderWriter) GetFeeForMessage(ctx context.Context, msg string) (uint64, error) { + ret := _m.Called(ctx, msg) + + if len(ret) == 0 { + panic("no return value specified for GetFeeForMessage") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (uint64, error)); ok { + return rf(ctx, msg) + } + if rf, ok := ret.Get(0).(func(context.Context, string) uint64); ok { + r0 = rf(ctx, msg) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, msg) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_GetFeeForMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFeeForMessage' +type ReaderWriter_GetFeeForMessage_Call struct { + *mock.Call +} + +// GetFeeForMessage is a helper method to define mock.On call +// - ctx context.Context +// - msg string +func (_e *ReaderWriter_Expecter) GetFeeForMessage(ctx interface{}, msg interface{}) *ReaderWriter_GetFeeForMessage_Call { + return &ReaderWriter_GetFeeForMessage_Call{Call: _e.mock.On("GetFeeForMessage", ctx, msg)} +} + +func (_c *ReaderWriter_GetFeeForMessage_Call) Run(run func(ctx context.Context, msg string)) *ReaderWriter_GetFeeForMessage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *ReaderWriter_GetFeeForMessage_Call) Return(_a0 uint64, _a1 error) *ReaderWriter_GetFeeForMessage_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_GetFeeForMessage_Call) RunAndReturn(run func(context.Context, string) (uint64, error)) *ReaderWriter_GetFeeForMessage_Call { + _c.Call.Return(run) + return _c +} + +// GetLatestBlock provides a mock function with given fields: ctx +func (_m *ReaderWriter) GetLatestBlock(ctx context.Context) (*rpc.GetBlockResult, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetLatestBlock") + } + + var r0 *rpc.GetBlockResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*rpc.GetBlockResult, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *rpc.GetBlockResult); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetBlockResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_GetLatestBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestBlock' +type ReaderWriter_GetLatestBlock_Call struct { + *mock.Call +} + +// GetLatestBlock is a helper method to define mock.On call +// - ctx context.Context +func (_e *ReaderWriter_Expecter) GetLatestBlock(ctx interface{}) *ReaderWriter_GetLatestBlock_Call { + return &ReaderWriter_GetLatestBlock_Call{Call: _e.mock.On("GetLatestBlock", ctx)} +} + +func (_c *ReaderWriter_GetLatestBlock_Call) Run(run func(ctx context.Context)) *ReaderWriter_GetLatestBlock_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *ReaderWriter_GetLatestBlock_Call) Return(_a0 *rpc.GetBlockResult, _a1 error) *ReaderWriter_GetLatestBlock_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_GetLatestBlock_Call) RunAndReturn(run func(context.Context) (*rpc.GetBlockResult, error)) *ReaderWriter_GetLatestBlock_Call { + _c.Call.Return(run) + return _c +} + +// LatestBlockhash provides a mock function with given fields: ctx +func (_m *ReaderWriter) LatestBlockhash(ctx context.Context) (*rpc.GetLatestBlockhashResult, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for LatestBlockhash") + } + + var r0 *rpc.GetLatestBlockhashResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*rpc.GetLatestBlockhashResult, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *rpc.GetLatestBlockhashResult); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.GetLatestBlockhashResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_LatestBlockhash_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestBlockhash' +type ReaderWriter_LatestBlockhash_Call struct { + *mock.Call +} + +// LatestBlockhash is a helper method to define mock.On call +// - ctx context.Context +func (_e *ReaderWriter_Expecter) LatestBlockhash(ctx interface{}) *ReaderWriter_LatestBlockhash_Call { + return &ReaderWriter_LatestBlockhash_Call{Call: _e.mock.On("LatestBlockhash", ctx)} +} + +func (_c *ReaderWriter_LatestBlockhash_Call) Run(run func(ctx context.Context)) *ReaderWriter_LatestBlockhash_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *ReaderWriter_LatestBlockhash_Call) Return(_a0 *rpc.GetLatestBlockhashResult, _a1 error) *ReaderWriter_LatestBlockhash_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_LatestBlockhash_Call) RunAndReturn(run func(context.Context) (*rpc.GetLatestBlockhashResult, error)) *ReaderWriter_LatestBlockhash_Call { + _c.Call.Return(run) + return _c +} + +// SendTx provides a mock function with given fields: ctx, tx +func (_m *ReaderWriter) SendTx(ctx context.Context, tx *solana.Transaction) (solana.Signature, error) { + ret := _m.Called(ctx, tx) + + if len(ret) == 0 { + panic("no return value specified for SendTx") + } + + var r0 solana.Signature + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *solana.Transaction) (solana.Signature, error)); ok { + return rf(ctx, tx) + } + if rf, ok := ret.Get(0).(func(context.Context, *solana.Transaction) solana.Signature); ok { + r0 = rf(ctx, tx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(solana.Signature) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *solana.Transaction) error); ok { + r1 = rf(ctx, tx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_SendTx_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendTx' +type ReaderWriter_SendTx_Call struct { + *mock.Call +} + +// SendTx is a helper method to define mock.On call +// - ctx context.Context +// - tx *solana.Transaction +func (_e *ReaderWriter_Expecter) SendTx(ctx interface{}, tx interface{}) *ReaderWriter_SendTx_Call { + return &ReaderWriter_SendTx_Call{Call: _e.mock.On("SendTx", ctx, tx)} +} + +func (_c *ReaderWriter_SendTx_Call) Run(run func(ctx context.Context, tx *solana.Transaction)) *ReaderWriter_SendTx_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*solana.Transaction)) + }) + return _c +} + +func (_c *ReaderWriter_SendTx_Call) Return(_a0 solana.Signature, _a1 error) *ReaderWriter_SendTx_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_SendTx_Call) RunAndReturn(run func(context.Context, *solana.Transaction) (solana.Signature, error)) *ReaderWriter_SendTx_Call { + _c.Call.Return(run) + return _c +} + +// SignatureStatuses provides a mock function with given fields: ctx, sigs +func (_m *ReaderWriter) SignatureStatuses(ctx context.Context, sigs []solana.Signature) ([]*rpc.SignatureStatusesResult, error) { + ret := _m.Called(ctx, sigs) + + if len(ret) == 0 { + panic("no return value specified for SignatureStatuses") + } + + var r0 []*rpc.SignatureStatusesResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, []solana.Signature) ([]*rpc.SignatureStatusesResult, error)); ok { + return rf(ctx, sigs) + } + if rf, ok := ret.Get(0).(func(context.Context, []solana.Signature) []*rpc.SignatureStatusesResult); ok { + r0 = rf(ctx, sigs) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*rpc.SignatureStatusesResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, []solana.Signature) error); ok { + r1 = rf(ctx, sigs) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_SignatureStatuses_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SignatureStatuses' +type ReaderWriter_SignatureStatuses_Call struct { + *mock.Call +} + +// SignatureStatuses is a helper method to define mock.On call +// - ctx context.Context +// - sigs []solana.Signature +func (_e *ReaderWriter_Expecter) SignatureStatuses(ctx interface{}, sigs interface{}) *ReaderWriter_SignatureStatuses_Call { + return &ReaderWriter_SignatureStatuses_Call{Call: _e.mock.On("SignatureStatuses", ctx, sigs)} +} + +func (_c *ReaderWriter_SignatureStatuses_Call) Run(run func(ctx context.Context, sigs []solana.Signature)) *ReaderWriter_SignatureStatuses_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].([]solana.Signature)) + }) + return _c +} + +func (_c *ReaderWriter_SignatureStatuses_Call) Return(_a0 []*rpc.SignatureStatusesResult, _a1 error) *ReaderWriter_SignatureStatuses_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_SignatureStatuses_Call) RunAndReturn(run func(context.Context, []solana.Signature) ([]*rpc.SignatureStatusesResult, error)) *ReaderWriter_SignatureStatuses_Call { + _c.Call.Return(run) + return _c +} + +// SimulateTx provides a mock function with given fields: ctx, tx, opts +func (_m *ReaderWriter) SimulateTx(ctx context.Context, tx *solana.Transaction, opts *rpc.SimulateTransactionOpts) (*rpc.SimulateTransactionResult, error) { + ret := _m.Called(ctx, tx, opts) + + if len(ret) == 0 { + panic("no return value specified for SimulateTx") + } + + var r0 *rpc.SimulateTransactionResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *solana.Transaction, *rpc.SimulateTransactionOpts) (*rpc.SimulateTransactionResult, error)); ok { + return rf(ctx, tx, opts) + } + if rf, ok := ret.Get(0).(func(context.Context, *solana.Transaction, *rpc.SimulateTransactionOpts) *rpc.SimulateTransactionResult); ok { + r0 = rf(ctx, tx, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*rpc.SimulateTransactionResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *solana.Transaction, *rpc.SimulateTransactionOpts) error); ok { + r1 = rf(ctx, tx, opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_SimulateTx_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SimulateTx' +type ReaderWriter_SimulateTx_Call struct { + *mock.Call +} + +// SimulateTx is a helper method to define mock.On call +// - ctx context.Context +// - tx *solana.Transaction +// - opts *rpc.SimulateTransactionOpts +func (_e *ReaderWriter_Expecter) SimulateTx(ctx interface{}, tx interface{}, opts interface{}) *ReaderWriter_SimulateTx_Call { + return &ReaderWriter_SimulateTx_Call{Call: _e.mock.On("SimulateTx", ctx, tx, opts)} +} + +func (_c *ReaderWriter_SimulateTx_Call) Run(run func(ctx context.Context, tx *solana.Transaction, opts *rpc.SimulateTransactionOpts)) *ReaderWriter_SimulateTx_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*solana.Transaction), args[2].(*rpc.SimulateTransactionOpts)) + }) + return _c +} + +func (_c *ReaderWriter_SimulateTx_Call) Return(_a0 *rpc.SimulateTransactionResult, _a1 error) *ReaderWriter_SimulateTx_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_SimulateTx_Call) RunAndReturn(run func(context.Context, *solana.Transaction, *rpc.SimulateTransactionOpts) (*rpc.SimulateTransactionResult, error)) *ReaderWriter_SimulateTx_Call { + _c.Call.Return(run) + return _c +} + +// SlotHeight provides a mock function with given fields: ctx +func (_m *ReaderWriter) SlotHeight(ctx context.Context) (uint64, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for SlotHeight") + } + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) uint64); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ReaderWriter_SlotHeight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SlotHeight' +type ReaderWriter_SlotHeight_Call struct { + *mock.Call +} + +// SlotHeight is a helper method to define mock.On call +// - ctx context.Context +func (_e *ReaderWriter_Expecter) SlotHeight(ctx interface{}) *ReaderWriter_SlotHeight_Call { + return &ReaderWriter_SlotHeight_Call{Call: _e.mock.On("SlotHeight", ctx)} +} + +func (_c *ReaderWriter_SlotHeight_Call) Run(run func(ctx context.Context)) *ReaderWriter_SlotHeight_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *ReaderWriter_SlotHeight_Call) Return(_a0 uint64, _a1 error) *ReaderWriter_SlotHeight_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ReaderWriter_SlotHeight_Call) RunAndReturn(run func(context.Context) (uint64, error)) *ReaderWriter_SlotHeight_Call { + _c.Call.Return(run) + return _c +} + +// NewReaderWriter creates a new instance of ReaderWriter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewReaderWriter(t interface { + mock.TestingT + Cleanup(func()) +}) *ReaderWriter { + mock := &ReaderWriter{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/solana/client/test_helpers.go b/pkg/solana/client/test_helpers.go index 02d03183f..5bb8b1cde 100644 --- a/pkg/solana/client/test_helpers.go +++ b/pkg/solana/client/test_helpers.go @@ -33,7 +33,7 @@ func SetupLocalSolNodeWithFlags(t *testing.T, flags ...string) (string, string) faucetPort := utils.MustRandomPort(t) url := "http://127.0.0.1:" + port - wsUrl := "ws://127.0.0.1:" + strconv.Itoa(portInt+1) + wsURL := "ws://127.0.0.1:" + strconv.Itoa(portInt+1) args := append([]string{ "--reset", @@ -76,7 +76,7 @@ func SetupLocalSolNodeWithFlags(t *testing.T, flags ...string) (string, string) } require.True(t, ready) - return url, wsUrl + return url, wsURL } func FundTestAccounts(t *testing.T, keys []solana.PublicKey, url string) { diff --git a/pkg/solana/config/config.go b/pkg/solana/config/config.go index 28d7ac5fb..7700b7a64 100644 --- a/pkg/solana/config/config.go +++ b/pkg/solana/config/config.go @@ -35,7 +35,6 @@ var defaultConfigSet = Chain{ EstimateComputeUnitLimit: ptr(false), // set to false to disable compute unit limit estimation } -//go:generate mockery --name Config --output ./mocks/ --case=underscore --filename config.go type Config interface { BalancePollPeriod() time.Duration ConfirmPollPeriod() time.Duration diff --git a/pkg/solana/config/mocks/config.go b/pkg/solana/config/mocks/config.go index feef5c3c6..6f9ab913d 100644 --- a/pkg/solana/config/mocks/config.go +++ b/pkg/solana/config/mocks/config.go @@ -14,6 +14,14 @@ type Config struct { mock.Mock } +type Config_Expecter struct { + mock *mock.Mock +} + +func (_m *Config) EXPECT() *Config_Expecter { + return &Config_Expecter{mock: &_m.Mock} +} + // BalancePollPeriod provides a mock function with given fields: func (_m *Config) BalancePollPeriod() time.Duration { ret := _m.Called() @@ -32,6 +40,33 @@ func (_m *Config) BalancePollPeriod() time.Duration { return r0 } +// Config_BalancePollPeriod_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BalancePollPeriod' +type Config_BalancePollPeriod_Call struct { + *mock.Call +} + +// BalancePollPeriod is a helper method to define mock.On call +func (_e *Config_Expecter) BalancePollPeriod() *Config_BalancePollPeriod_Call { + return &Config_BalancePollPeriod_Call{Call: _e.mock.On("BalancePollPeriod")} +} + +func (_c *Config_BalancePollPeriod_Call) Run(run func()) *Config_BalancePollPeriod_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_BalancePollPeriod_Call) Return(_a0 time.Duration) *Config_BalancePollPeriod_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_BalancePollPeriod_Call) RunAndReturn(run func() time.Duration) *Config_BalancePollPeriod_Call { + _c.Call.Return(run) + return _c +} + // BlockHistoryPollPeriod provides a mock function with given fields: func (_m *Config) BlockHistoryPollPeriod() time.Duration { ret := _m.Called() @@ -50,6 +85,33 @@ func (_m *Config) BlockHistoryPollPeriod() time.Duration { return r0 } +// Config_BlockHistoryPollPeriod_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockHistoryPollPeriod' +type Config_BlockHistoryPollPeriod_Call struct { + *mock.Call +} + +// BlockHistoryPollPeriod is a helper method to define mock.On call +func (_e *Config_Expecter) BlockHistoryPollPeriod() *Config_BlockHistoryPollPeriod_Call { + return &Config_BlockHistoryPollPeriod_Call{Call: _e.mock.On("BlockHistoryPollPeriod")} +} + +func (_c *Config_BlockHistoryPollPeriod_Call) Run(run func()) *Config_BlockHistoryPollPeriod_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_BlockHistoryPollPeriod_Call) Return(_a0 time.Duration) *Config_BlockHistoryPollPeriod_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_BlockHistoryPollPeriod_Call) RunAndReturn(run func() time.Duration) *Config_BlockHistoryPollPeriod_Call { + _c.Call.Return(run) + return _c +} + // BlockHistorySize provides a mock function with given fields: func (_m *Config) BlockHistorySize() uint64 { ret := _m.Called() @@ -68,6 +130,33 @@ func (_m *Config) BlockHistorySize() uint64 { return r0 } +// Config_BlockHistorySize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockHistorySize' +type Config_BlockHistorySize_Call struct { + *mock.Call +} + +// BlockHistorySize is a helper method to define mock.On call +func (_e *Config_Expecter) BlockHistorySize() *Config_BlockHistorySize_Call { + return &Config_BlockHistorySize_Call{Call: _e.mock.On("BlockHistorySize")} +} + +func (_c *Config_BlockHistorySize_Call) Run(run func()) *Config_BlockHistorySize_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_BlockHistorySize_Call) Return(_a0 uint64) *Config_BlockHistorySize_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_BlockHistorySize_Call) RunAndReturn(run func() uint64) *Config_BlockHistorySize_Call { + _c.Call.Return(run) + return _c +} + // Commitment provides a mock function with given fields: func (_m *Config) Commitment() rpc.CommitmentType { ret := _m.Called() @@ -86,6 +175,33 @@ func (_m *Config) Commitment() rpc.CommitmentType { return r0 } +// Config_Commitment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Commitment' +type Config_Commitment_Call struct { + *mock.Call +} + +// Commitment is a helper method to define mock.On call +func (_e *Config_Expecter) Commitment() *Config_Commitment_Call { + return &Config_Commitment_Call{Call: _e.mock.On("Commitment")} +} + +func (_c *Config_Commitment_Call) Run(run func()) *Config_Commitment_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_Commitment_Call) Return(_a0 rpc.CommitmentType) *Config_Commitment_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_Commitment_Call) RunAndReturn(run func() rpc.CommitmentType) *Config_Commitment_Call { + _c.Call.Return(run) + return _c +} + // ComputeUnitLimitDefault provides a mock function with given fields: func (_m *Config) ComputeUnitLimitDefault() uint32 { ret := _m.Called() @@ -104,6 +220,33 @@ func (_m *Config) ComputeUnitLimitDefault() uint32 { return r0 } +// Config_ComputeUnitLimitDefault_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputeUnitLimitDefault' +type Config_ComputeUnitLimitDefault_Call struct { + *mock.Call +} + +// ComputeUnitLimitDefault is a helper method to define mock.On call +func (_e *Config_Expecter) ComputeUnitLimitDefault() *Config_ComputeUnitLimitDefault_Call { + return &Config_ComputeUnitLimitDefault_Call{Call: _e.mock.On("ComputeUnitLimitDefault")} +} + +func (_c *Config_ComputeUnitLimitDefault_Call) Run(run func()) *Config_ComputeUnitLimitDefault_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_ComputeUnitLimitDefault_Call) Return(_a0 uint32) *Config_ComputeUnitLimitDefault_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_ComputeUnitLimitDefault_Call) RunAndReturn(run func() uint32) *Config_ComputeUnitLimitDefault_Call { + _c.Call.Return(run) + return _c +} + // ComputeUnitPriceDefault provides a mock function with given fields: func (_m *Config) ComputeUnitPriceDefault() uint64 { ret := _m.Called() @@ -122,6 +265,33 @@ func (_m *Config) ComputeUnitPriceDefault() uint64 { return r0 } +// Config_ComputeUnitPriceDefault_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputeUnitPriceDefault' +type Config_ComputeUnitPriceDefault_Call struct { + *mock.Call +} + +// ComputeUnitPriceDefault is a helper method to define mock.On call +func (_e *Config_Expecter) ComputeUnitPriceDefault() *Config_ComputeUnitPriceDefault_Call { + return &Config_ComputeUnitPriceDefault_Call{Call: _e.mock.On("ComputeUnitPriceDefault")} +} + +func (_c *Config_ComputeUnitPriceDefault_Call) Run(run func()) *Config_ComputeUnitPriceDefault_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_ComputeUnitPriceDefault_Call) Return(_a0 uint64) *Config_ComputeUnitPriceDefault_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_ComputeUnitPriceDefault_Call) RunAndReturn(run func() uint64) *Config_ComputeUnitPriceDefault_Call { + _c.Call.Return(run) + return _c +} + // ComputeUnitPriceMax provides a mock function with given fields: func (_m *Config) ComputeUnitPriceMax() uint64 { ret := _m.Called() @@ -140,6 +310,33 @@ func (_m *Config) ComputeUnitPriceMax() uint64 { return r0 } +// Config_ComputeUnitPriceMax_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputeUnitPriceMax' +type Config_ComputeUnitPriceMax_Call struct { + *mock.Call +} + +// ComputeUnitPriceMax is a helper method to define mock.On call +func (_e *Config_Expecter) ComputeUnitPriceMax() *Config_ComputeUnitPriceMax_Call { + return &Config_ComputeUnitPriceMax_Call{Call: _e.mock.On("ComputeUnitPriceMax")} +} + +func (_c *Config_ComputeUnitPriceMax_Call) Run(run func()) *Config_ComputeUnitPriceMax_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_ComputeUnitPriceMax_Call) Return(_a0 uint64) *Config_ComputeUnitPriceMax_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_ComputeUnitPriceMax_Call) RunAndReturn(run func() uint64) *Config_ComputeUnitPriceMax_Call { + _c.Call.Return(run) + return _c +} + // ComputeUnitPriceMin provides a mock function with given fields: func (_m *Config) ComputeUnitPriceMin() uint64 { ret := _m.Called() @@ -158,6 +355,33 @@ func (_m *Config) ComputeUnitPriceMin() uint64 { return r0 } +// Config_ComputeUnitPriceMin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputeUnitPriceMin' +type Config_ComputeUnitPriceMin_Call struct { + *mock.Call +} + +// ComputeUnitPriceMin is a helper method to define mock.On call +func (_e *Config_Expecter) ComputeUnitPriceMin() *Config_ComputeUnitPriceMin_Call { + return &Config_ComputeUnitPriceMin_Call{Call: _e.mock.On("ComputeUnitPriceMin")} +} + +func (_c *Config_ComputeUnitPriceMin_Call) Run(run func()) *Config_ComputeUnitPriceMin_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_ComputeUnitPriceMin_Call) Return(_a0 uint64) *Config_ComputeUnitPriceMin_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_ComputeUnitPriceMin_Call) RunAndReturn(run func() uint64) *Config_ComputeUnitPriceMin_Call { + _c.Call.Return(run) + return _c +} + // ConfirmPollPeriod provides a mock function with given fields: func (_m *Config) ConfirmPollPeriod() time.Duration { ret := _m.Called() @@ -176,6 +400,33 @@ func (_m *Config) ConfirmPollPeriod() time.Duration { return r0 } +// Config_ConfirmPollPeriod_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConfirmPollPeriod' +type Config_ConfirmPollPeriod_Call struct { + *mock.Call +} + +// ConfirmPollPeriod is a helper method to define mock.On call +func (_e *Config_Expecter) ConfirmPollPeriod() *Config_ConfirmPollPeriod_Call { + return &Config_ConfirmPollPeriod_Call{Call: _e.mock.On("ConfirmPollPeriod")} +} + +func (_c *Config_ConfirmPollPeriod_Call) Run(run func()) *Config_ConfirmPollPeriod_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_ConfirmPollPeriod_Call) Return(_a0 time.Duration) *Config_ConfirmPollPeriod_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_ConfirmPollPeriod_Call) RunAndReturn(run func() time.Duration) *Config_ConfirmPollPeriod_Call { + _c.Call.Return(run) + return _c +} + // EstimateComputeUnitLimit provides a mock function with given fields: func (_m *Config) EstimateComputeUnitLimit() bool { ret := _m.Called() @@ -194,6 +445,33 @@ func (_m *Config) EstimateComputeUnitLimit() bool { return r0 } +// Config_EstimateComputeUnitLimit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EstimateComputeUnitLimit' +type Config_EstimateComputeUnitLimit_Call struct { + *mock.Call +} + +// EstimateComputeUnitLimit is a helper method to define mock.On call +func (_e *Config_Expecter) EstimateComputeUnitLimit() *Config_EstimateComputeUnitLimit_Call { + return &Config_EstimateComputeUnitLimit_Call{Call: _e.mock.On("EstimateComputeUnitLimit")} +} + +func (_c *Config_EstimateComputeUnitLimit_Call) Run(run func()) *Config_EstimateComputeUnitLimit_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_EstimateComputeUnitLimit_Call) Return(_a0 bool) *Config_EstimateComputeUnitLimit_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_EstimateComputeUnitLimit_Call) RunAndReturn(run func() bool) *Config_EstimateComputeUnitLimit_Call { + _c.Call.Return(run) + return _c +} + // FeeBumpPeriod provides a mock function with given fields: func (_m *Config) FeeBumpPeriod() time.Duration { ret := _m.Called() @@ -212,6 +490,33 @@ func (_m *Config) FeeBumpPeriod() time.Duration { return r0 } +// Config_FeeBumpPeriod_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FeeBumpPeriod' +type Config_FeeBumpPeriod_Call struct { + *mock.Call +} + +// FeeBumpPeriod is a helper method to define mock.On call +func (_e *Config_Expecter) FeeBumpPeriod() *Config_FeeBumpPeriod_Call { + return &Config_FeeBumpPeriod_Call{Call: _e.mock.On("FeeBumpPeriod")} +} + +func (_c *Config_FeeBumpPeriod_Call) Run(run func()) *Config_FeeBumpPeriod_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_FeeBumpPeriod_Call) Return(_a0 time.Duration) *Config_FeeBumpPeriod_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_FeeBumpPeriod_Call) RunAndReturn(run func() time.Duration) *Config_FeeBumpPeriod_Call { + _c.Call.Return(run) + return _c +} + // FeeEstimatorMode provides a mock function with given fields: func (_m *Config) FeeEstimatorMode() string { ret := _m.Called() @@ -230,6 +535,33 @@ func (_m *Config) FeeEstimatorMode() string { return r0 } +// Config_FeeEstimatorMode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FeeEstimatorMode' +type Config_FeeEstimatorMode_Call struct { + *mock.Call +} + +// FeeEstimatorMode is a helper method to define mock.On call +func (_e *Config_Expecter) FeeEstimatorMode() *Config_FeeEstimatorMode_Call { + return &Config_FeeEstimatorMode_Call{Call: _e.mock.On("FeeEstimatorMode")} +} + +func (_c *Config_FeeEstimatorMode_Call) Run(run func()) *Config_FeeEstimatorMode_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_FeeEstimatorMode_Call) Return(_a0 string) *Config_FeeEstimatorMode_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_FeeEstimatorMode_Call) RunAndReturn(run func() string) *Config_FeeEstimatorMode_Call { + _c.Call.Return(run) + return _c +} + // MaxRetries provides a mock function with given fields: func (_m *Config) MaxRetries() *uint { ret := _m.Called() @@ -250,6 +582,33 @@ func (_m *Config) MaxRetries() *uint { return r0 } +// Config_MaxRetries_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MaxRetries' +type Config_MaxRetries_Call struct { + *mock.Call +} + +// MaxRetries is a helper method to define mock.On call +func (_e *Config_Expecter) MaxRetries() *Config_MaxRetries_Call { + return &Config_MaxRetries_Call{Call: _e.mock.On("MaxRetries")} +} + +func (_c *Config_MaxRetries_Call) Run(run func()) *Config_MaxRetries_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_MaxRetries_Call) Return(_a0 *uint) *Config_MaxRetries_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_MaxRetries_Call) RunAndReturn(run func() *uint) *Config_MaxRetries_Call { + _c.Call.Return(run) + return _c +} + // OCR2CachePollPeriod provides a mock function with given fields: func (_m *Config) OCR2CachePollPeriod() time.Duration { ret := _m.Called() @@ -268,6 +627,33 @@ func (_m *Config) OCR2CachePollPeriod() time.Duration { return r0 } +// Config_OCR2CachePollPeriod_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OCR2CachePollPeriod' +type Config_OCR2CachePollPeriod_Call struct { + *mock.Call +} + +// OCR2CachePollPeriod is a helper method to define mock.On call +func (_e *Config_Expecter) OCR2CachePollPeriod() *Config_OCR2CachePollPeriod_Call { + return &Config_OCR2CachePollPeriod_Call{Call: _e.mock.On("OCR2CachePollPeriod")} +} + +func (_c *Config_OCR2CachePollPeriod_Call) Run(run func()) *Config_OCR2CachePollPeriod_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_OCR2CachePollPeriod_Call) Return(_a0 time.Duration) *Config_OCR2CachePollPeriod_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_OCR2CachePollPeriod_Call) RunAndReturn(run func() time.Duration) *Config_OCR2CachePollPeriod_Call { + _c.Call.Return(run) + return _c +} + // OCR2CacheTTL provides a mock function with given fields: func (_m *Config) OCR2CacheTTL() time.Duration { ret := _m.Called() @@ -286,6 +672,33 @@ func (_m *Config) OCR2CacheTTL() time.Duration { return r0 } +// Config_OCR2CacheTTL_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OCR2CacheTTL' +type Config_OCR2CacheTTL_Call struct { + *mock.Call +} + +// OCR2CacheTTL is a helper method to define mock.On call +func (_e *Config_Expecter) OCR2CacheTTL() *Config_OCR2CacheTTL_Call { + return &Config_OCR2CacheTTL_Call{Call: _e.mock.On("OCR2CacheTTL")} +} + +func (_c *Config_OCR2CacheTTL_Call) Run(run func()) *Config_OCR2CacheTTL_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_OCR2CacheTTL_Call) Return(_a0 time.Duration) *Config_OCR2CacheTTL_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_OCR2CacheTTL_Call) RunAndReturn(run func() time.Duration) *Config_OCR2CacheTTL_Call { + _c.Call.Return(run) + return _c +} + // SkipPreflight provides a mock function with given fields: func (_m *Config) SkipPreflight() bool { ret := _m.Called() @@ -304,6 +717,33 @@ func (_m *Config) SkipPreflight() bool { return r0 } +// Config_SkipPreflight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SkipPreflight' +type Config_SkipPreflight_Call struct { + *mock.Call +} + +// SkipPreflight is a helper method to define mock.On call +func (_e *Config_Expecter) SkipPreflight() *Config_SkipPreflight_Call { + return &Config_SkipPreflight_Call{Call: _e.mock.On("SkipPreflight")} +} + +func (_c *Config_SkipPreflight_Call) Run(run func()) *Config_SkipPreflight_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_SkipPreflight_Call) Return(_a0 bool) *Config_SkipPreflight_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_SkipPreflight_Call) RunAndReturn(run func() bool) *Config_SkipPreflight_Call { + _c.Call.Return(run) + return _c +} + // TxConfirmTimeout provides a mock function with given fields: func (_m *Config) TxConfirmTimeout() time.Duration { ret := _m.Called() @@ -322,6 +762,33 @@ func (_m *Config) TxConfirmTimeout() time.Duration { return r0 } +// Config_TxConfirmTimeout_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TxConfirmTimeout' +type Config_TxConfirmTimeout_Call struct { + *mock.Call +} + +// TxConfirmTimeout is a helper method to define mock.On call +func (_e *Config_Expecter) TxConfirmTimeout() *Config_TxConfirmTimeout_Call { + return &Config_TxConfirmTimeout_Call{Call: _e.mock.On("TxConfirmTimeout")} +} + +func (_c *Config_TxConfirmTimeout_Call) Run(run func()) *Config_TxConfirmTimeout_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_TxConfirmTimeout_Call) Return(_a0 time.Duration) *Config_TxConfirmTimeout_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_TxConfirmTimeout_Call) RunAndReturn(run func() time.Duration) *Config_TxConfirmTimeout_Call { + _c.Call.Return(run) + return _c +} + // TxRetentionTimeout provides a mock function with given fields: func (_m *Config) TxRetentionTimeout() time.Duration { ret := _m.Called() @@ -340,6 +807,33 @@ func (_m *Config) TxRetentionTimeout() time.Duration { return r0 } +// Config_TxRetentionTimeout_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TxRetentionTimeout' +type Config_TxRetentionTimeout_Call struct { + *mock.Call +} + +// TxRetentionTimeout is a helper method to define mock.On call +func (_e *Config_Expecter) TxRetentionTimeout() *Config_TxRetentionTimeout_Call { + return &Config_TxRetentionTimeout_Call{Call: _e.mock.On("TxRetentionTimeout")} +} + +func (_c *Config_TxRetentionTimeout_Call) Run(run func()) *Config_TxRetentionTimeout_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_TxRetentionTimeout_Call) Return(_a0 time.Duration) *Config_TxRetentionTimeout_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_TxRetentionTimeout_Call) RunAndReturn(run func() time.Duration) *Config_TxRetentionTimeout_Call { + _c.Call.Return(run) + return _c +} + // TxRetryTimeout provides a mock function with given fields: func (_m *Config) TxRetryTimeout() time.Duration { ret := _m.Called() @@ -358,6 +852,33 @@ func (_m *Config) TxRetryTimeout() time.Duration { return r0 } +// Config_TxRetryTimeout_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TxRetryTimeout' +type Config_TxRetryTimeout_Call struct { + *mock.Call +} + +// TxRetryTimeout is a helper method to define mock.On call +func (_e *Config_Expecter) TxRetryTimeout() *Config_TxRetryTimeout_Call { + return &Config_TxRetryTimeout_Call{Call: _e.mock.On("TxRetryTimeout")} +} + +func (_c *Config_TxRetryTimeout_Call) Run(run func()) *Config_TxRetryTimeout_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_TxRetryTimeout_Call) Return(_a0 time.Duration) *Config_TxRetryTimeout_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_TxRetryTimeout_Call) RunAndReturn(run func() time.Duration) *Config_TxRetryTimeout_Call { + _c.Call.Return(run) + return _c +} + // TxTimeout provides a mock function with given fields: func (_m *Config) TxTimeout() time.Duration { ret := _m.Called() @@ -376,6 +897,33 @@ func (_m *Config) TxTimeout() time.Duration { return r0 } +// Config_TxTimeout_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TxTimeout' +type Config_TxTimeout_Call struct { + *mock.Call +} + +// TxTimeout is a helper method to define mock.On call +func (_e *Config_Expecter) TxTimeout() *Config_TxTimeout_Call { + return &Config_TxTimeout_Call{Call: _e.mock.On("TxTimeout")} +} + +func (_c *Config_TxTimeout_Call) Run(run func()) *Config_TxTimeout_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Config_TxTimeout_Call) Return(_a0 time.Duration) *Config_TxTimeout_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Config_TxTimeout_Call) RunAndReturn(run func() time.Duration) *Config_TxTimeout_Call { + _c.Call.Return(run) + return _c +} + // NewConfig creates a new instance of Config. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewConfig(t interface { diff --git a/pkg/solana/fees/estimator.go b/pkg/solana/fees/estimator.go index aded6f4a6..f09fec95b 100644 --- a/pkg/solana/fees/estimator.go +++ b/pkg/solana/fees/estimator.go @@ -2,7 +2,6 @@ package fees import "context" -//go:generate mockery --name Estimator --output ./mocks/ type Estimator interface { Start(context.Context) error Close() error diff --git a/pkg/solana/fees/mocks/Estimator.go b/pkg/solana/fees/mocks/Estimator.go index a61b811a7..06d6a53ae 100644 --- a/pkg/solana/fees/mocks/Estimator.go +++ b/pkg/solana/fees/mocks/Estimator.go @@ -13,6 +13,14 @@ type Estimator struct { mock.Mock } +type Estimator_Expecter struct { + mock *mock.Mock +} + +func (_m *Estimator) EXPECT() *Estimator_Expecter { + return &Estimator_Expecter{mock: &_m.Mock} +} + // BaseComputeUnitPrice provides a mock function with given fields: func (_m *Estimator) BaseComputeUnitPrice() uint64 { ret := _m.Called() @@ -31,6 +39,33 @@ func (_m *Estimator) BaseComputeUnitPrice() uint64 { return r0 } +// Estimator_BaseComputeUnitPrice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BaseComputeUnitPrice' +type Estimator_BaseComputeUnitPrice_Call struct { + *mock.Call +} + +// BaseComputeUnitPrice is a helper method to define mock.On call +func (_e *Estimator_Expecter) BaseComputeUnitPrice() *Estimator_BaseComputeUnitPrice_Call { + return &Estimator_BaseComputeUnitPrice_Call{Call: _e.mock.On("BaseComputeUnitPrice")} +} + +func (_c *Estimator_BaseComputeUnitPrice_Call) Run(run func()) *Estimator_BaseComputeUnitPrice_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Estimator_BaseComputeUnitPrice_Call) Return(_a0 uint64) *Estimator_BaseComputeUnitPrice_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Estimator_BaseComputeUnitPrice_Call) RunAndReturn(run func() uint64) *Estimator_BaseComputeUnitPrice_Call { + _c.Call.Return(run) + return _c +} + // Close provides a mock function with given fields: func (_m *Estimator) Close() error { ret := _m.Called() @@ -49,6 +84,33 @@ func (_m *Estimator) Close() error { return r0 } +// Estimator_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' +type Estimator_Close_Call struct { + *mock.Call +} + +// Close is a helper method to define mock.On call +func (_e *Estimator_Expecter) Close() *Estimator_Close_Call { + return &Estimator_Close_Call{Call: _e.mock.On("Close")} +} + +func (_c *Estimator_Close_Call) Run(run func()) *Estimator_Close_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Estimator_Close_Call) Return(_a0 error) *Estimator_Close_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Estimator_Close_Call) RunAndReturn(run func() error) *Estimator_Close_Call { + _c.Call.Return(run) + return _c +} + // Start provides a mock function with given fields: _a0 func (_m *Estimator) Start(_a0 context.Context) error { ret := _m.Called(_a0) @@ -67,6 +129,34 @@ func (_m *Estimator) Start(_a0 context.Context) error { return r0 } +// Estimator_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' +type Estimator_Start_Call struct { + *mock.Call +} + +// Start is a helper method to define mock.On call +// - _a0 context.Context +func (_e *Estimator_Expecter) Start(_a0 interface{}) *Estimator_Start_Call { + return &Estimator_Start_Call{Call: _e.mock.On("Start", _a0)} +} + +func (_c *Estimator_Start_Call) Run(run func(_a0 context.Context)) *Estimator_Start_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *Estimator_Start_Call) Return(_a0 error) *Estimator_Start_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Estimator_Start_Call) RunAndReturn(run func(context.Context) error) *Estimator_Start_Call { + _c.Call.Return(run) + return _c +} + // NewEstimator creates a new instance of Estimator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewEstimator(t interface { diff --git a/pkg/solana/logpoller/parser.go b/pkg/solana/logpoller/parser.go index 3367ba3a3..c70124fe1 100644 --- a/pkg/solana/logpoller/parser.go +++ b/pkg/solana/logpoller/parser.go @@ -173,7 +173,7 @@ func parse(logs []string) []ProgramOutput { if len(matches) == 3 { if depth == 1 { if val, err := strconv.Atoi(matches[1]); err == nil { - instLogs[len(instLogs)-1].ComputeUnits = uint(val) + instLogs[len(instLogs)-1].ComputeUnits = uint(val) //nolint:gosec } } diff --git a/pkg/solana/logpoller/worker.go b/pkg/solana/logpoller/worker.go index 73d1b421e..ef97306bf 100644 --- a/pkg/solana/logpoller/worker.go +++ b/pkg/solana/logpoller/worker.go @@ -188,9 +188,9 @@ func (g *WorkerGroup) runRetryQueue(ctx context.Context) { case job := <-g.chRetry: var retry retryableJob - switch job.(type) { + switch typedJob := job.(type) { case retryableJob: - retry = job.(retryableJob) + retry = typedJob retry.count++ if retry.count > g.maxRetryCount { diff --git a/pkg/solana/logpoller/worker_test.go b/pkg/solana/logpoller/worker_test.go index 7dd6c5dd0..63b1d5254 100644 --- a/pkg/solana/logpoller/worker_test.go +++ b/pkg/solana/logpoller/worker_test.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller" ) @@ -21,7 +22,7 @@ func TestWorkerGroup(t *testing.T) { ctx := tests.Context(t) group := logpoller.NewWorkerGroup(5, logger.Nop()) - group.Start(ctx) + require.NoError(t, group.Start(ctx)) t.Cleanup(func() { require.NoError(t, group.Close()) }) @@ -49,7 +50,7 @@ func TestWorkerGroup_Retry(t *testing.T) { ctx := tests.Context(t) group := logpoller.NewWorkerGroup(5, logger.Nop()) - group.Start(ctx) + require.NoError(t, group.Start(ctx)) t.Cleanup(func() { require.NoError(t, group.Close()) }) @@ -103,7 +104,7 @@ func TestWorkerGroup_Close(t *testing.T) { ctx := tests.Context(t) group := logpoller.NewWorkerGroup(5, logger.Nop()) - group.Start(ctx) + require.NoError(t, group.Start(ctx)) output := make([]int, 10) @@ -147,12 +148,12 @@ func TestWorkerGroup_DoContext(t *testing.T) { require.NoError(t, group.Start(ctx)) t.Run("if input context cancelled", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) + ctxB, cancel := context.WithCancel(ctx) // calling cancel before calling Do should result in an error cancel() - require.ErrorIs(t, group.Do(ctx, job), logpoller.ErrContextCancelled) + require.ErrorIs(t, group.Do(ctxB, job), logpoller.ErrContextCancelled) }) t.Run("if queue closed", func(t *testing.T) { diff --git a/pkg/solana/txm/mocks/simple_keystore.go b/pkg/solana/txm/mocks/simple_keystore.go index 1c0bd6562..655869cd7 100644 --- a/pkg/solana/txm/mocks/simple_keystore.go +++ b/pkg/solana/txm/mocks/simple_keystore.go @@ -13,6 +13,14 @@ type SimpleKeystore struct { mock.Mock } +type SimpleKeystore_Expecter struct { + mock *mock.Mock +} + +func (_m *SimpleKeystore) EXPECT() *SimpleKeystore_Expecter { + return &SimpleKeystore_Expecter{mock: &_m.Mock} +} + // Accounts provides a mock function with given fields: ctx func (_m *SimpleKeystore) Accounts(ctx context.Context) ([]string, error) { ret := _m.Called(ctx) @@ -43,6 +51,34 @@ func (_m *SimpleKeystore) Accounts(ctx context.Context) ([]string, error) { return r0, r1 } +// SimpleKeystore_Accounts_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Accounts' +type SimpleKeystore_Accounts_Call struct { + *mock.Call +} + +// Accounts is a helper method to define mock.On call +// - ctx context.Context +func (_e *SimpleKeystore_Expecter) Accounts(ctx interface{}) *SimpleKeystore_Accounts_Call { + return &SimpleKeystore_Accounts_Call{Call: _e.mock.On("Accounts", ctx)} +} + +func (_c *SimpleKeystore_Accounts_Call) Run(run func(ctx context.Context)) *SimpleKeystore_Accounts_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *SimpleKeystore_Accounts_Call) Return(accounts []string, err error) *SimpleKeystore_Accounts_Call { + _c.Call.Return(accounts, err) + return _c +} + +func (_c *SimpleKeystore_Accounts_Call) RunAndReturn(run func(context.Context) ([]string, error)) *SimpleKeystore_Accounts_Call { + _c.Call.Return(run) + return _c +} + // Sign provides a mock function with given fields: ctx, account, data func (_m *SimpleKeystore) Sign(ctx context.Context, account string, data []byte) ([]byte, error) { ret := _m.Called(ctx, account, data) @@ -73,6 +109,36 @@ func (_m *SimpleKeystore) Sign(ctx context.Context, account string, data []byte) return r0, r1 } +// SimpleKeystore_Sign_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Sign' +type SimpleKeystore_Sign_Call struct { + *mock.Call +} + +// Sign is a helper method to define mock.On call +// - ctx context.Context +// - account string +// - data []byte +func (_e *SimpleKeystore_Expecter) Sign(ctx interface{}, account interface{}, data interface{}) *SimpleKeystore_Sign_Call { + return &SimpleKeystore_Sign_Call{Call: _e.mock.On("Sign", ctx, account, data)} +} + +func (_c *SimpleKeystore_Sign_Call) Run(run func(ctx context.Context, account string, data []byte)) *SimpleKeystore_Sign_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].([]byte)) + }) + return _c +} + +func (_c *SimpleKeystore_Sign_Call) Return(signature []byte, err error) *SimpleKeystore_Sign_Call { + _c.Call.Return(signature, err) + return _c +} + +func (_c *SimpleKeystore_Sign_Call) RunAndReturn(run func(context.Context, string, []byte) ([]byte, error)) *SimpleKeystore_Sign_Call { + _c.Call.Return(run) + return _c +} + // NewSimpleKeystore creates a new instance of SimpleKeystore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewSimpleKeystore(t interface { diff --git a/pkg/solana/txm/txm.go b/pkg/solana/txm/txm.go index 2a99a6c44..dd27743c5 100644 --- a/pkg/solana/txm/txm.go +++ b/pkg/solana/txm/txm.go @@ -37,7 +37,6 @@ const ( var _ services.Service = (*Txm)(nil) -//go:generate mockery --name SimpleKeystore --output ./mocks/ --case=underscore --filename simple_keystore.go type SimpleKeystore interface { Sign(ctx context.Context, account string, data []byte) (signature []byte, err error) Accounts(ctx context.Context) (accounts []string, err error) From b26be2e9f922082b37f51782091163bf43bbffec Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Thu, 31 Oct 2024 09:30:46 -0500 Subject: [PATCH 04/19] mockery was not running as part of command go install github.com/vektra/mockery/v2@v2.43.2 mockery --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 27f3f7d31..7bbe4b2e0 100644 --- a/Makefile +++ b/Makefile @@ -103,6 +103,7 @@ gomodtidy: gomods .PHONY: mockery mockery: $(mockery) ## Install mockery. go install github.com/vektra/mockery/v2@v2.43.2 + mockery .PHONY: rm-mocked rm-mocked: From d6ab5112053b710278d8e04186f5627dd07076cc Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Mon, 4 Nov 2024 09:58:34 -0600 Subject: [PATCH 05/19] change interface/function names and update mocks --- pkg/solana/logpoller/job.go | 17 ++++--- pkg/solana/logpoller/loader.go | 13 +++-- pkg/solana/logpoller/loader_test.go | 4 +- pkg/solana/logpoller/mocks/parser.go | 26 +++++----- pkg/solana/logpoller/mocks/rpc_client.go | 60 ------------------------ pkg/solana/logpoller/parser.go | 2 +- 6 files changed, 32 insertions(+), 90 deletions(-) diff --git a/pkg/solana/logpoller/job.go b/pkg/solana/logpoller/job.go index 0d47d1084..fe87b10dd 100644 --- a/pkg/solana/logpoller/job.go +++ b/pkg/solana/logpoller/job.go @@ -42,7 +42,7 @@ type eventDetail struct { // processEventJob is a job that processes a single event. The parser should be a pure function // such that no network requests are made and no side effects are produced. type processEventJob struct { - parser Parser + parser ProgramEventProcessor event ProgramEvent } @@ -51,7 +51,7 @@ func (j *processEventJob) String() string { } func (j *processEventJob) Run(_ context.Context) error { - return j.parser.ProcessEvent(j.event) + return j.parser.Process(j.event) } // getTransactionsFromBlockJob is a job that fetches transaction signatures from a block and loads @@ -59,7 +59,7 @@ func (j *processEventJob) Run(_ context.Context) error { type getTransactionsFromBlockJob struct { slotNumber uint64 client RPCClient - parser Parser + parser ProgramEventProcessor chJobs chan Job } @@ -105,8 +105,11 @@ func (j *getTransactionsFromBlockJob) Run(ctx context.Context) error { } detail := eventDetail{ - blockNumber: *block.BlockHeight, - blockHash: block.Blockhash, + blockHash: block.Blockhash, + } + + if block.BlockHeight != nil { + detail.blockNumber = *block.BlockHeight } for idx, trx := range block.Transactions { @@ -121,9 +124,9 @@ func (j *getTransactionsFromBlockJob) Run(ctx context.Context) error { return nil } -func messagesToEvents(messages []string, parser Parser, detail eventDetail, chJobs chan Job) { +func messagesToEvents(messages []string, parser ProgramEventProcessor, detail eventDetail, chJobs chan Job) { var logIdx uint - for _, outputs := range parse(messages) { + for _, outputs := range parseProgramLogs(messages) { for _, event := range outputs.Events { logIdx++ diff --git a/pkg/solana/logpoller/loader.go b/pkg/solana/logpoller/loader.go index 1fb2ff469..7a78afd4a 100644 --- a/pkg/solana/logpoller/loader.go +++ b/pkg/solana/logpoller/loader.go @@ -14,13 +14,13 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" ) -type Parser interface { - // ProcessEvent should take a ProgramEvent and parse it based on log signature +type ProgramEventProcessor interface { + // Process should take a ProgramEvent and parseProgramLogs it based on log signature // and expected encoding. Only return errors that cannot be handled and // should exit further transaction processing on the running thread. // - // ProcessEvent should be thread safe. - ProcessEvent(ProgramEvent) error + // Process should be thread safe. + Process(ProgramEvent) error } type RPCClient interface { @@ -28,7 +28,6 @@ type RPCClient interface { GetBlocks(ctx context.Context, startSlot uint64, endSlot *uint64, commitment rpc.CommitmentType) (out rpc.BlocksResult, err error) GetBlockWithOpts(context.Context, uint64, *rpc.GetBlockOpts) (*rpc.GetBlockResult, error) GetSignaturesForAddressWithOpts(context.Context, solana.PublicKey, *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error) - GetTransaction(context.Context, solana.Signature, *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error) } const ( @@ -42,7 +41,7 @@ type EncodedLogCollector struct { // dependencies and configuration client RPCClient - parser Parser + parser ProgramEventProcessor lggr logger.Logger rpcTimeLimit time.Duration @@ -61,7 +60,7 @@ type EncodedLogCollector struct { func NewEncodedLogCollector( client RPCClient, - parser Parser, + parser ProgramEventProcessor, lggr logger.Logger, ) *EncodedLogCollector { c := &EncodedLogCollector{ diff --git a/pkg/solana/logpoller/loader_test.go b/pkg/solana/logpoller/loader_test.go index d6636e3ce..32defd97e 100644 --- a/pkg/solana/logpoller/loader_test.go +++ b/pkg/solana/logpoller/loader_test.go @@ -33,7 +33,7 @@ var ( func TestEncodedLogCollector_StartClose(t *testing.T) { client := new(mocks.RPCClient) - parser := new(mocks.Parser) + parser := new(mocks.ProgramEventProcessor) ctx := tests.Context(t) collector := logpoller.NewEncodedLogCollector(client, parser, logger.Nop()) @@ -273,7 +273,7 @@ type testParser struct { count atomic.Uint64 } -func (p *testParser) ProcessEvent(event logpoller.ProgramEvent) error { +func (p *testParser) Process(event logpoller.ProgramEvent) error { p.called.Store(true) p.count.Store(p.count.Load() + 1) diff --git a/pkg/solana/logpoller/mocks/parser.go b/pkg/solana/logpoller/mocks/parser.go index 07f0b2e41..45455c429 100644 --- a/pkg/solana/logpoller/mocks/parser.go +++ b/pkg/solana/logpoller/mocks/parser.go @@ -7,8 +7,8 @@ import ( mock "github.com/stretchr/testify/mock" ) -// Parser is an autogenerated mock type for the Parser type -type Parser struct { +// ProgramEventProcessor is an autogenerated mock type for the ProgramEventProcessor type +type ProgramEventProcessor struct { mock.Mock } @@ -16,16 +16,16 @@ type Parser_Expecter struct { mock *mock.Mock } -func (_m *Parser) EXPECT() *Parser_Expecter { +func (_m *ProgramEventProcessor) EXPECT() *Parser_Expecter { return &Parser_Expecter{mock: &_m.Mock} } -// ProcessEvent provides a mock function with given fields: _a0 -func (_m *Parser) ProcessEvent(_a0 logpoller.ProgramEvent) error { +// Process provides a mock function with given fields: _a0 +func (_m *ProgramEventProcessor) Process(_a0 logpoller.ProgramEvent) error { ret := _m.Called(_a0) if len(ret) == 0 { - panic("no return value specified for ProcessEvent") + panic("no return value specified for Process") } var r0 error @@ -38,15 +38,15 @@ func (_m *Parser) ProcessEvent(_a0 logpoller.ProgramEvent) error { return r0 } -// Parser_ProcessEvent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProcessEvent' +// Parser_ProcessEvent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Process' type Parser_ProcessEvent_Call struct { *mock.Call } -// ProcessEvent is a helper method to define mock.On call +// Process is a helper method to define mock.On call // - _a0 logpoller.ProgramEvent -func (_e *Parser_Expecter) ProcessEvent(_a0 interface{}) *Parser_ProcessEvent_Call { - return &Parser_ProcessEvent_Call{Call: _e.mock.On("ProcessEvent", _a0)} +func (_e *Parser_Expecter) Process(_a0 interface{}) *Parser_ProcessEvent_Call { + return &Parser_ProcessEvent_Call{Call: _e.mock.On("Process", _a0)} } func (_c *Parser_ProcessEvent_Call) Run(run func(_a0 logpoller.ProgramEvent)) *Parser_ProcessEvent_Call { @@ -66,13 +66,13 @@ func (_c *Parser_ProcessEvent_Call) RunAndReturn(run func(logpoller.ProgramEvent return _c } -// NewParser creates a new instance of Parser. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// NewParser creates a new instance of ProgramEventProcessor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewParser(t interface { mock.TestingT Cleanup(func()) -}) *Parser { - mock := &Parser{} +}) *ProgramEventProcessor { + mock := &ProgramEventProcessor{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/pkg/solana/logpoller/mocks/rpc_client.go b/pkg/solana/logpoller/mocks/rpc_client.go index f296e1d26..851eba9ec 100644 --- a/pkg/solana/logpoller/mocks/rpc_client.go +++ b/pkg/solana/logpoller/mocks/rpc_client.go @@ -265,66 +265,6 @@ func (_c *RPCClient_GetSignaturesForAddressWithOpts_Call) RunAndReturn(run func( return _c } -// GetTransaction provides a mock function with given fields: _a0, _a1, _a2 -func (_m *RPCClient) GetTransaction(_a0 context.Context, _a1 solana.Signature, _a2 *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error) { - ret := _m.Called(_a0, _a1, _a2) - - if len(ret) == 0 { - panic("no return value specified for GetTransaction") - } - - var r0 *rpc.GetTransactionResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error)); ok { - return rf(_a0, _a1, _a2) - } - if rf, ok := ret.Get(0).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) *rpc.GetTransactionResult); ok { - r0 = rf(_a0, _a1, _a2) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rpc.GetTransactionResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, solana.Signature, *rpc.GetTransactionOpts) error); ok { - r1 = rf(_a0, _a1, _a2) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// RPCClient_GetTransaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTransaction' -type RPCClient_GetTransaction_Call struct { - *mock.Call -} - -// GetTransaction is a helper method to define mock.On call -// - _a0 context.Context -// - _a1 solana.Signature -// - _a2 *rpc.GetTransactionOpts -func (_e *RPCClient_Expecter) GetTransaction(_a0 interface{}, _a1 interface{}, _a2 interface{}) *RPCClient_GetTransaction_Call { - return &RPCClient_GetTransaction_Call{Call: _e.mock.On("GetTransaction", _a0, _a1, _a2)} -} - -func (_c *RPCClient_GetTransaction_Call) Run(run func(_a0 context.Context, _a1 solana.Signature, _a2 *rpc.GetTransactionOpts)) *RPCClient_GetTransaction_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(solana.Signature), args[2].(*rpc.GetTransactionOpts)) - }) - return _c -} - -func (_c *RPCClient_GetTransaction_Call) Return(_a0 *rpc.GetTransactionResult, _a1 error) *RPCClient_GetTransaction_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *RPCClient_GetTransaction_Call) RunAndReturn(run func(context.Context, solana.Signature, *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error)) *RPCClient_GetTransaction_Call { - _c.Call.Return(run) - return _c -} - // NewRPCClient creates a new instance of RPCClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewRPCClient(t interface { diff --git a/pkg/solana/logpoller/parser.go b/pkg/solana/logpoller/parser.go index c70124fe1..13d69809d 100644 --- a/pkg/solana/logpoller/parser.go +++ b/pkg/solana/logpoller/parser.go @@ -66,7 +66,7 @@ Program data: HDQnaQjSWwkNAAAASGVsbG8sIFdvcmxkISoAAAAAAAAA // base64 encoded; bo Program J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4 consumed 1477 of 200000 compute units Program J1zQwrBNBngz26jRPNWsUSZMHJwBwpkoDitXRV95LdK4 success */ -func parse(logs []string) []ProgramOutput { +func parseProgramLogs(logs []string) []ProgramOutput { var depth int instLogs := []ProgramOutput{} From cd5ced659092882deb12ca225295dfb0eb8b3802 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Tue, 5 Nov 2024 09:35:39 -0600 Subject: [PATCH 06/19] change to atomic values instead of single mutex --- pkg/solana/logpoller/loader.go | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/pkg/solana/logpoller/loader.go b/pkg/solana/logpoller/loader.go index 7a78afd4a..e152a6bd6 100644 --- a/pkg/solana/logpoller/loader.go +++ b/pkg/solana/logpoller/loader.go @@ -3,7 +3,6 @@ package logpoller import ( "context" "errors" - "sync" "sync/atomic" "time" @@ -51,10 +50,9 @@ type EncodedLogCollector struct { chJobs chan Job workers *WorkerGroup - mu sync.RWMutex loadingBlocks atomic.Bool - highestSlot uint64 - highestSlotLoaded uint64 + highestSlot atomic.Uint64 + highestSlotLoaded atomic.Uint64 lastSentSlot atomic.Uint64 } @@ -141,6 +139,8 @@ func (c *EncodedLogCollector) runSlotPolling(ctx context.Context) { select { case <-ctx.Done(): + timer.Stop() + return case <-timer.C: ctxB, cancel := context.WithTimeout(ctx, c.rpcTimeLimit) @@ -175,10 +175,8 @@ func (c *EncodedLogCollector) runSlotProcessing(ctx context.Context) { case <-ctx.Done(): return case slot := <-c.chSlot: - c.mu.Lock() - - if slot > c.highestSlot { - c.highestSlot = slot + if slot > c.highestSlot.Load() { + c.highestSlot.Store(slot) if !c.loadingBlocks.Load() { c.loadingBlocks.Store(true) @@ -196,14 +194,10 @@ func (c *EncodedLogCollector) runSlotProcessing(ctx context.Context) { return } - c.mu.Lock() - c.highestSlotLoaded = end - c.mu.Unlock() - }(c.highestSlotLoaded+1, c.highestSlot) + c.highestSlotLoaded.Store(end) + }(c.highestSlotLoaded.Load()+1, slot) } } - - c.mu.Unlock() } } } From 9105785474a06ab5d664990e49d2578e7e5690c2 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Tue, 5 Nov 2024 10:36:25 -0600 Subject: [PATCH 07/19] fix mocked output --- .mockery.yaml | 16 +++++++++---- integration-tests/smoke/event_loader_test.go | 2 +- .../{parser.go => program_event_processor.go} | 24 +++++++++---------- 3 files changed, 24 insertions(+), 18 deletions(-) rename pkg/solana/logpoller/mocks/{parser.go => program_event_processor.go} (52%) diff --git a/.mockery.yaml b/.mockery.yaml index cc28bbec1..41ca45696 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -10,6 +10,8 @@ packages: interfaces: FeedBalances: Fees: + config: + filename: "Fees.go" NetworkFees: NodeBalances: NodeSuccess: @@ -21,17 +23,21 @@ packages: github.com/smartcontractkit/chainlink-solana/pkg/solana/config: interfaces: Config: - filename: config.go - case: underscore + config: + filename: config.go + case: underscore github.com/smartcontractkit/chainlink-solana/pkg/solana/logpoller: interfaces: RPCClient: - Parser: + ProgramEventProcessor: github.com/smartcontractkit/chainlink-solana/pkg/solana/fees: interfaces: Estimator: + config: + filename: "Estimator.go" github.com/smartcontractkit/chainlink-solana/pkg/solana/txm: interfaces: SimpleKeystore: - filename: simple_keystore.go - case: underscore \ No newline at end of file + config: + filename: simple_keystore.go + case: underscore \ No newline at end of file diff --git a/integration-tests/smoke/event_loader_test.go b/integration-tests/smoke/event_loader_test.go index 7ced52a7f..cd4bc678c 100644 --- a/integration-tests/smoke/event_loader_test.go +++ b/integration-tests/smoke/event_loader_test.go @@ -143,7 +143,7 @@ type printParser struct { values []uint64 } -func (p *printParser) ProcessEvent(evt logpoller.ProgramEvent) error { +func (p *printParser) Process(evt logpoller.ProgramEvent) error { p.t.Helper() data, err := base64.StdEncoding.DecodeString(evt.Data) diff --git a/pkg/solana/logpoller/mocks/parser.go b/pkg/solana/logpoller/mocks/program_event_processor.go similarity index 52% rename from pkg/solana/logpoller/mocks/parser.go rename to pkg/solana/logpoller/mocks/program_event_processor.go index 45455c429..4af8fb77a 100644 --- a/pkg/solana/logpoller/mocks/parser.go +++ b/pkg/solana/logpoller/mocks/program_event_processor.go @@ -12,12 +12,12 @@ type ProgramEventProcessor struct { mock.Mock } -type Parser_Expecter struct { +type ProgramEventProcessor_Expecter struct { mock *mock.Mock } -func (_m *ProgramEventProcessor) EXPECT() *Parser_Expecter { - return &Parser_Expecter{mock: &_m.Mock} +func (_m *ProgramEventProcessor) EXPECT() *ProgramEventProcessor_Expecter { + return &ProgramEventProcessor_Expecter{mock: &_m.Mock} } // Process provides a mock function with given fields: _a0 @@ -38,37 +38,37 @@ func (_m *ProgramEventProcessor) Process(_a0 logpoller.ProgramEvent) error { return r0 } -// Parser_ProcessEvent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Process' -type Parser_ProcessEvent_Call struct { +// ProgramEventProcessor_Process_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Process' +type ProgramEventProcessor_Process_Call struct { *mock.Call } // Process is a helper method to define mock.On call // - _a0 logpoller.ProgramEvent -func (_e *Parser_Expecter) Process(_a0 interface{}) *Parser_ProcessEvent_Call { - return &Parser_ProcessEvent_Call{Call: _e.mock.On("Process", _a0)} +func (_e *ProgramEventProcessor_Expecter) Process(_a0 interface{}) *ProgramEventProcessor_Process_Call { + return &ProgramEventProcessor_Process_Call{Call: _e.mock.On("Process", _a0)} } -func (_c *Parser_ProcessEvent_Call) Run(run func(_a0 logpoller.ProgramEvent)) *Parser_ProcessEvent_Call { +func (_c *ProgramEventProcessor_Process_Call) Run(run func(_a0 logpoller.ProgramEvent)) *ProgramEventProcessor_Process_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(logpoller.ProgramEvent)) }) return _c } -func (_c *Parser_ProcessEvent_Call) Return(_a0 error) *Parser_ProcessEvent_Call { +func (_c *ProgramEventProcessor_Process_Call) Return(_a0 error) *ProgramEventProcessor_Process_Call { _c.Call.Return(_a0) return _c } -func (_c *Parser_ProcessEvent_Call) RunAndReturn(run func(logpoller.ProgramEvent) error) *Parser_ProcessEvent_Call { +func (_c *ProgramEventProcessor_Process_Call) RunAndReturn(run func(logpoller.ProgramEvent) error) *ProgramEventProcessor_Process_Call { _c.Call.Return(run) return _c } -// NewParser creates a new instance of ProgramEventProcessor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// NewProgramEventProcessor creates a new instance of ProgramEventProcessor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. -func NewParser(t interface { +func NewProgramEventProcessor(t interface { mock.TestingT Cleanup(func()) }) *ProgramEventProcessor { From 3a5cc73ac0a5ea04a5dc1a9aa3fcdf19f7012724 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Tue, 5 Nov 2024 10:55:00 -0600 Subject: [PATCH 08/19] fix race test --- pkg/solana/logpoller/worker.go | 2 +- pkg/solana/logpoller/worker_test.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pkg/solana/logpoller/worker.go b/pkg/solana/logpoller/worker.go index ef97306bf..531f85936 100644 --- a/pkg/solana/logpoller/worker.go +++ b/pkg/solana/logpoller/worker.go @@ -237,10 +237,10 @@ func (g *WorkerGroup) runRetries(ctx context.Context) { return case <-timer.C: + g.mu.RLock() keys := make([]string, 0, len(g.retryMap)) retries := make([]retryableJob, 0, len(g.retryMap)) - g.mu.RLock() for key, retry := range g.retryMap { if time.Now().After(retry.when) { keys = append(keys, key) diff --git a/pkg/solana/logpoller/worker_test.go b/pkg/solana/logpoller/worker_test.go index 63b1d5254..8c527b201 100644 --- a/pkg/solana/logpoller/worker_test.go +++ b/pkg/solana/logpoller/worker_test.go @@ -27,11 +27,15 @@ func TestWorkerGroup(t *testing.T) { require.NoError(t, group.Close()) }) + var mu sync.RWMutex output := make([]int, 10) for idx := range output { job := testJob{ job: func(ctx context.Context) error { + mu.Lock() + defer mu.Unlock() + output[idx] = 1 return nil @@ -42,6 +46,9 @@ func TestWorkerGroup(t *testing.T) { } tests.AssertEventually(t, func() bool { + mu.RLock() + defer mu.RUnlock() + return reflect.DeepEqual([]int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, output) }) } @@ -106,10 +113,14 @@ func TestWorkerGroup_Close(t *testing.T) { require.NoError(t, group.Start(ctx)) + var mu sync.RWMutex output := make([]int, 10) for idx := range output { _ = group.Do(ctx, testJob{job: func(ctx context.Context) error { + mu.Lock() + defer mu.Unlock() + // make one run longer than the wait time if idx == 9 { timer := time.NewTimer(time.Second) @@ -136,7 +147,10 @@ func TestWorkerGroup_Close(t *testing.T) { // wait for the first 9 to finish and close the group time.Sleep(100 * time.Millisecond) group.Close() + + mu.RLock() assert.Equal(t, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 0}, output) + mu.RUnlock() } func TestWorkerGroup_DoContext(t *testing.T) { From ac810cc89cc92d674b2e6605a9bbcad152f6325a Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Tue, 5 Nov 2024 11:11:53 -0600 Subject: [PATCH 09/19] fix flaky test --- pkg/solana/logpoller/worker_test.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pkg/solana/logpoller/worker_test.go b/pkg/solana/logpoller/worker_test.go index 8c527b201..d287b5e7f 100644 --- a/pkg/solana/logpoller/worker_test.go +++ b/pkg/solana/logpoller/worker_test.go @@ -149,8 +149,20 @@ func TestWorkerGroup_Close(t *testing.T) { group.Close() mu.RLock() - assert.Equal(t, []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 0}, output) + var finished int + var notFinished int + + for _, val := range output { + if val == 1 { + finished++ + } else if val == 0 { + notFinished++ + } + } mu.RUnlock() + + assert.GreaterOrEqual(t, finished, 1) + assert.GreaterOrEqual(t, notFinished, 1) } func TestWorkerGroup_DoContext(t *testing.T) { From c24e01a6409874262425cb40a76c8009584457f3 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Tue, 5 Nov 2024 13:25:50 -0600 Subject: [PATCH 10/19] reduction of almost 100 ns/op by pre-allocating workers in constructor --- pkg/solana/logpoller/worker.go | 30 ++++++++++------------------- pkg/solana/logpoller/worker_test.go | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/pkg/solana/logpoller/worker.go b/pkg/solana/logpoller/worker.go index 531f85936..f17e3ad20 100644 --- a/pkg/solana/logpoller/worker.go +++ b/pkg/solana/logpoller/worker.go @@ -62,7 +62,6 @@ type WorkerGroup struct { lggr logger.Logger // worker group state - activeWorkers int workers chan *worker queue *queue[Job] input chan Job @@ -97,6 +96,15 @@ func NewWorkerGroup(workers int, lggr logger.Logger) *WorkerGroup { Close: g.close, }.NewServiceEngine(lggr) + for idx := range workers { + g.workers <- &worker{ + Name: fmt.Sprintf("worker-%d", idx+1), + Queue: g.workers, + Retry: g.chRetry, + Lggr: g.lggr, + } + } + return g } @@ -286,26 +294,8 @@ func (g *WorkerGroup) processQueue(ctx context.Context) { } func (g *WorkerGroup) doJob(ctx context.Context, job Job) { - var wkr *worker - - // no read or write locks on activeWorkers or maxWorkers because it's - // assumed the job loop is a single process reading from the job queue - if g.activeWorkers < g.maxWorkers { - // create a new worker - wkr = &worker{ - Name: fmt.Sprintf("worker-%d", g.activeWorkers+1), - Queue: g.workers, - Retry: g.chRetry, - Lggr: g.lggr, - } - - g.activeWorkers++ - } else { - // wait for a worker to be available - wkr = <-g.workers - } + wkr := <-g.workers - // have worker do the work go wkr.Do(ctx, job) } diff --git a/pkg/solana/logpoller/worker_test.go b/pkg/solana/logpoller/worker_test.go index d287b5e7f..b6d967ce7 100644 --- a/pkg/solana/logpoller/worker_test.go +++ b/pkg/solana/logpoller/worker_test.go @@ -190,6 +190,26 @@ func TestWorkerGroup_DoContext(t *testing.T) { }) } +func BenchmarkWorkerGroup(b *testing.B) { + ctx := tests.Context(b) + + group := logpoller.NewWorkerGroup(100, logger.Nop()) + job := testJob{job: func(ctx context.Context) error { return nil }} + + require.NoError(b, group.Start(ctx)) + + defer func() { + require.NoError(b, group.Close()) + }() + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _ = group.Do(ctx, job) + } +} + type testJob struct { job func(context.Context) error } From ffa172c53afe7381261ed9e52b95daceebffc09d Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Wed, 6 Nov 2024 10:07:23 -0600 Subject: [PATCH 11/19] Upgrade Go in Anchor Contract Build Action Go version 1.23 causes a broken build for `anchor-go`, resulting in not being able to install the `anchor-go` tooling. Version 1.22.8 is the highest version that is still compatible. The tool `anchor-go` also has a higher version available `v0.3.1`, but this is also a broken build and results in unusable generated code with multiple errors. --- contracts/generated/log_read_test/CreateLog.go | 10 +++++----- scripts/build-contract-artifacts-action.sh | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/contracts/generated/log_read_test/CreateLog.go b/contracts/generated/log_read_test/CreateLog.go index 25a488ac7..45b0d3317 100644 --- a/contracts/generated/log_read_test/CreateLog.go +++ b/contracts/generated/log_read_test/CreateLog.go @@ -17,7 +17,7 @@ type CreateLog struct { // [0] = [SIGNER] authority // // [1] = [] systemProgram - ag_solanago.AccountMetaSlice `bin:"-"` + ag_solanago.AccountMetaSlice `bin:"-" borsh_skip:"true"` } // NewCreateLogInstructionBuilder creates a new `CreateLog` instruction builder. @@ -42,7 +42,7 @@ func (inst *CreateLog) SetAuthorityAccount(authority ag_solanago.PublicKey) *Cre // GetAuthorityAccount gets the "authority" account. func (inst *CreateLog) GetAuthorityAccount() *ag_solanago.AccountMeta { - return inst.AccountMetaSlice.Get(0) + return inst.AccountMetaSlice[0] } // SetSystemProgramAccount sets the "systemProgram" account. @@ -53,7 +53,7 @@ func (inst *CreateLog) SetSystemProgramAccount(systemProgram ag_solanago.PublicK // GetSystemProgramAccount gets the "systemProgram" account. func (inst *CreateLog) GetSystemProgramAccount() *ag_solanago.AccountMeta { - return inst.AccountMetaSlice.Get(1) + return inst.AccountMetaSlice[1] } func (inst CreateLog) Build() *Instruction { @@ -108,8 +108,8 @@ func (inst *CreateLog) EncodeToTree(parent ag_treeout.Branches) { // Accounts of the instruction: instructionBranch.Child("Accounts[len=2]").ParentFunc(func(accountsBranch ag_treeout.Branches) { - accountsBranch.Child(ag_format.Meta(" authority", inst.AccountMetaSlice.Get(0))) - accountsBranch.Child(ag_format.Meta("systemProgram", inst.AccountMetaSlice.Get(1))) + accountsBranch.Child(ag_format.Meta(" authority", inst.AccountMetaSlice[0])) + accountsBranch.Child(ag_format.Meta("systemProgram", inst.AccountMetaSlice[1])) }) }) }) diff --git a/scripts/build-contract-artifacts-action.sh b/scripts/build-contract-artifacts-action.sh index 4aa2781b3..379628b43 100755 --- a/scripts/build-contract-artifacts-action.sh +++ b/scripts/build-contract-artifacts-action.sh @@ -11,8 +11,8 @@ CONTRACTS=${REPO}/contracts # install go apt-get update apt-get install -y wget -wget https://golang.org/dl/go1.21.7.linux-amd64.tar.gz -tar -xvf go1.21.7.linux-amd64.tar.gz +wget https://golang.org/dl/go1.22.8.linux-amd64.tar.gz +tar -xvf go1.22.8.linux-amd64.tar.gz mv go /usr/local export PATH=/usr/local/go/bin:$PATH export GOPATH=$HOME/go From dbec5bb81fdfb6eafd8769a9595e82d263c44e6b Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Thu, 7 Nov 2024 09:17:51 -0600 Subject: [PATCH 12/19] addressed feedback --- pkg/solana/logpoller/job.go | 4 +- pkg/solana/logpoller/loader.go | 50 ++++++++++++------------ pkg/solana/logpoller/parser.go | 59 ++++++++++++++++++++++------- pkg/solana/logpoller/worker.go | 16 +++----- pkg/solana/logpoller/worker_test.go | 12 +++++- 5 files changed, 87 insertions(+), 54 deletions(-) diff --git a/pkg/solana/logpoller/job.go b/pkg/solana/logpoller/job.go index fe87b10dd..09b3aefa5 100644 --- a/pkg/solana/logpoller/job.go +++ b/pkg/solana/logpoller/job.go @@ -131,8 +131,8 @@ func messagesToEvents(messages []string, parser ProgramEventProcessor, detail ev logIdx++ event.BlockNumber = detail.blockNumber - event.BlockHash = detail.blockHash.String() - event.TransactionHash = detail.trxSig.String() + event.BlockHash = detail.blockHash + event.TransactionHash = detail.trxSig event.TransactionIndex = detail.trxIdx event.TransactionLogIndex = logIdx diff --git a/pkg/solana/logpoller/loader.go b/pkg/solana/logpoller/loader.go index e152a6bd6..4757f73c4 100644 --- a/pkg/solana/logpoller/loader.go +++ b/pkg/solana/logpoller/loader.go @@ -50,7 +50,6 @@ type EncodedLogCollector struct { chJobs chan Job workers *WorkerGroup - loadingBlocks atomic.Bool highestSlot atomic.Uint64 highestSlotLoaded atomic.Uint64 lastSentSlot atomic.Uint64 @@ -64,7 +63,7 @@ func NewEncodedLogCollector( c := &EncodedLogCollector{ client: client, parser: parser, - chSlot: make(chan uint64, 1), + chSlot: make(chan uint64), chBlock: make(chan uint64, 1), chJobs: make(chan Job, 1), lggr: lggr, @@ -148,7 +147,7 @@ func (c *EncodedLogCollector) runSlotPolling(ctx context.Context) { // not to be run as a job, but as a blocking call result, err := c.client.GetLatestBlockhash(ctxB, rpc.CommitmentFinalized) if err != nil { - c.lggr.Info("failed to get latest blockhash", "err", err) + c.lggr.Error("failed to get latest blockhash", "err", err) cancel() continue @@ -162,7 +161,11 @@ func (c *EncodedLogCollector) runSlotPolling(ctx context.Context) { } c.lastSentSlot.Store(result.Context.Slot) - c.chSlot <- result.Context.Slot + + select { + case c.chSlot <- result.Context.Slot: + default: + } } timer.Stop() @@ -175,28 +178,11 @@ func (c *EncodedLogCollector) runSlotProcessing(ctx context.Context) { case <-ctx.Done(): return case slot := <-c.chSlot: - if slot > c.highestSlot.Load() { + if c.highestSlot.Load() < slot { c.highestSlot.Store(slot) - if !c.loadingBlocks.Load() { - c.loadingBlocks.Store(true) - - // run routine to load blocks in slot range - go func(start, end uint64) { - defer c.loadingBlocks.Store(false) - - if err := c.loadSlotBlocksRange(ctx, start, end); err != nil { - // TODO: probably log something here - // a retry will happen anyway on the next round of slots - // so the error is handled by doing nothing - c.lggr.Info("failed to load slot blocks range", "start", start, "end", end, "err", err) - - return - } - - c.highestSlotLoaded.Store(end) - }(c.highestSlotLoaded.Load()+1, slot) - } + // load blocks in slot range + c.loadRange(ctx, c.highestSlotLoaded.Load()+1, slot) } } } @@ -214,7 +200,7 @@ func (c *EncodedLogCollector) runBlockProcessing(ctx context.Context) { parser: c.parser, chJobs: c.chJobs, }); err != nil { - c.lggr.Infof("failed to add job to queue: %s", err) + c.lggr.Errorf("failed to add job to queue: %s", err) } } } @@ -227,12 +213,24 @@ func (c *EncodedLogCollector) runJobProcessing(ctx context.Context) { return case job := <-c.chJobs: if err := c.workers.Do(ctx, job); err != nil { - c.lggr.Infof("failed to add job to queue: %s", err) + c.lggr.Errorf("failed to add job to queue: %s", err) } } } } +func (c *EncodedLogCollector) loadRange(ctx context.Context, start, end uint64) { + if err := c.loadSlotBlocksRange(ctx, start, end); err != nil { + // a retry will happen anyway on the next round of slots + // so the error is handled by doing nothing + c.lggr.Error("failed to load slot blocks range", "start", start, "end", end, "err", err) + + return + } + + c.highestSlotLoaded.Store(end) +} + func (c *EncodedLogCollector) loadSlotBlocksRange(ctx context.Context, start, end uint64) error { ctx, cancel := context.WithTimeout(ctx, c.rpcTimeLimit) defer cancel() diff --git a/pkg/solana/logpoller/parser.go b/pkg/solana/logpoller/parser.go index 13d69809d..f42ef2e2b 100644 --- a/pkg/solana/logpoller/parser.go +++ b/pkg/solana/logpoller/parser.go @@ -5,6 +5,8 @@ import ( "regexp" "strconv" "strings" + + "github.com/gagliardetto/solana-go" ) type MessageStyle string @@ -26,8 +28,8 @@ var ( type BlockData struct { BlockNumber uint64 - BlockHash string - TransactionHash string + BlockHash solana.Hash + TransactionHash solana.Signature TransactionIndex int TransactionLogIndex uint } @@ -71,12 +73,13 @@ func parseProgramLogs(logs []string) []ProgramOutput { instLogs := []ProgramOutput{} lastEventIdx := -1 + lastLogIdx := -1 for _, log := range logs { if strings.HasPrefix(log, "Program log:") { logDataMatches := logMatcher.FindStringSubmatch(log) - if len(logDataMatches) <= 1 { + if len(logDataMatches) <= 1 || lastLogIdx < 0 { continue } @@ -84,31 +87,39 @@ func parseProgramLogs(logs []string) []ProgramOutput { if len(instructionMatches) > 1 { // is an event which should be followed by: Program data: (.*) - instLogs[len(instLogs)-1].Events = append(instLogs[len(instLogs)-1].Events, ProgramEvent{ + instLogs[lastLogIdx].Events = append(instLogs[lastLogIdx].Events, ProgramEvent{ Prefix: prefixBuilder(depth), FunctionName: instructionMatches[1], }) - lastEventIdx = len(instLogs[len(instLogs)-1].Events) - 1 + lastEventIdx = len(instLogs[lastLogIdx].Events) - 1 } else { // if contains: Instruction: (.*) this is an event and should be followed by: Program data: // else this is a log - instLogs[len(instLogs)-1].Logs = append(instLogs[len(instLogs)-1].Logs, ProgramLog{ + instLogs[lastLogIdx].Logs = append(instLogs[lastLogIdx].Logs, ProgramLog{ Prefix: prefixBuilder(depth), Style: MessageStyleMuted, Text: log, }) } } else if strings.HasPrefix(log, "Program data:") { + if lastLogIdx < 0 { + continue + } + dataMatches := dataMatcher.FindStringSubmatch(log) if len(dataMatches) > 1 { if lastEventIdx > -1 { - instLogs[len(instLogs)-1].Events[lastEventIdx].Data = dataMatches[1] + instLogs[lastLogIdx].Events[lastEventIdx].Data = dataMatches[1] } } } else if strings.HasPrefix(log, "Log truncated") { - instLogs[len(instLogs)-1].Truncated = true + if lastLogIdx < 0 { + continue + } + + instLogs[lastLogIdx].Truncated = true } else { matches := invokeMatcher.FindStringSubmatch(log) @@ -121,8 +132,14 @@ func parseProgramLogs(logs []string) []ProgramOutput { Logs: []ProgramLog{}, Truncated: false, }) + + lastLogIdx = len(instLogs) - 1 } else { - instLogs[len(instLogs)-1].Logs = append(instLogs[len(instLogs)-1].Logs, ProgramLog{ + if lastLogIdx < 0 { + continue + } + + instLogs[lastLogIdx].Logs = append(instLogs[lastLogIdx].Logs, ProgramLog{ Prefix: prefixBuilder(depth), Style: MessageStyleInfo, Text: fmt.Sprintf("Program invoked: %s", matches[1]), @@ -131,7 +148,11 @@ func parseProgramLogs(logs []string) []ProgramOutput { depth++ } else if strings.Contains(log, "success") { - instLogs[len(instLogs)-1].Logs = append(instLogs[len(instLogs)-1].Logs, ProgramLog{ + if lastLogIdx < 0 { + continue + } + + instLogs[lastLogIdx].Logs = append(instLogs[lastLogIdx].Logs, ProgramLog{ Prefix: prefixBuilder(depth), Style: MessageStyleSuccess, Text: "Program returned success", @@ -139,7 +160,11 @@ func parseProgramLogs(logs []string) []ProgramOutput { depth-- } else if strings.Contains(log, "failed") { - instLogs[len(instLogs)-1].Failed = true + if lastLogIdx < 0 { + continue + } + + instLogs[lastLogIdx].Failed = true idx := strings.Index(log, ": ") + 2 currText := fmt.Sprintf(`Program returned error: "%s"`, log[idx:]) @@ -151,7 +176,7 @@ func parseProgramLogs(logs []string) []ProgramOutput { currText = strings.ToTitle(log) } - instLogs[len(instLogs)-1].Logs = append(instLogs[len(instLogs)-1].Logs, ProgramLog{ + instLogs[lastLogIdx].Logs = append(instLogs[lastLogIdx].Logs, ProgramLog{ Prefix: prefixBuilder(depth), Style: MessageStyleWarning, Text: currText, @@ -167,13 +192,19 @@ func parseProgramLogs(logs []string) []ProgramOutput { Logs: []ProgramLog{}, Truncated: false, }) + + lastLogIdx = len(instLogs) - 1 + } + + if lastLogIdx < 0 { + continue } matches := consumedMatcher.FindStringSubmatch(log) if len(matches) == 3 { if depth == 1 { if val, err := strconv.Atoi(matches[1]); err == nil { - instLogs[len(instLogs)-1].ComputeUnits = uint(val) //nolint:gosec + instLogs[lastLogIdx].ComputeUnits = uint(val) //nolint:gosec } } @@ -181,7 +212,7 @@ func parseProgramLogs(logs []string) []ProgramOutput { } // native program logs don't start with "Program log:" - instLogs[len(instLogs)-1].Logs = append(instLogs[len(instLogs)-1].Logs, ProgramLog{ + instLogs[lastLogIdx].Logs = append(instLogs[lastLogIdx].Logs, ProgramLog{ Prefix: prefixBuilder(depth), Style: MessageStyleMuted, Text: log, diff --git a/pkg/solana/logpoller/worker.go b/pkg/solana/logpoller/worker.go index f17e3ad20..0e7d31df0 100644 --- a/pkg/solana/logpoller/worker.go +++ b/pkg/solana/logpoller/worker.go @@ -39,7 +39,7 @@ type worker struct { func (w *worker) Do(ctx context.Context, job Job) { if ctx.Err() == nil { if err := job.Run(ctx); err != nil { - w.Lggr.Infof("job %s failed with error; retrying: %s", job, err) + w.Lggr.Errorf("job %s failed with error; retrying: %s", job, err) w.Retry <- job } } @@ -182,10 +182,6 @@ Loop: break Loop } } - - // run the job queue one more time just in case some - // new work items snuck in - g.processQueue(ctx) } func (g *WorkerGroup) runRetryQueue(ctx context.Context) { @@ -202,19 +198,19 @@ func (g *WorkerGroup) runRetryQueue(ctx context.Context) { retry.count++ if retry.count > g.maxRetryCount { - g.lggr.Infof("job %s dropped after max retries", job) + g.lggr.Errorf("job %s dropped after max retries", job) continue } wait := calculateExponentialBackoff(retry.count) - g.lggr.Infof("retrying job in %dms", wait/time.Millisecond) + g.lggr.Errorf("retrying job in %dms", wait/time.Millisecond) retry.when = time.Now().Add(wait) default: wait := calculateExponentialBackoff(0) - g.lggr.Infof("retrying job %s in %dms", job, wait/time.Millisecond) + g.lggr.Errorf("retrying job %s in %s", job, wait) retry = retryableJob{ name: createRandomString(12), @@ -227,7 +223,7 @@ func (g *WorkerGroup) runRetryQueue(ctx context.Context) { g.retryMap[retry.name] = retry if len(g.retryMap) >= DefaultNotifyRetryDepth { - g.lggr.Infof("retry queue depth: %d", len(g.retryMap)) + g.lggr.Errorf("retry queue depth: %d", len(g.retryMap)) } g.mu.Unlock() } @@ -277,7 +273,7 @@ func (g *WorkerGroup) processQueue(ctx context.Context) { } if g.queue.Len() >= DefaultNotifyQueueDepth { - g.lggr.Infof("queue depth: %d", g.queue.Len()) + g.lggr.Errorf("queue depth: %d", g.queue.Len()) } value, err := g.queue.Pop() diff --git a/pkg/solana/logpoller/worker_test.go b/pkg/solana/logpoller/worker_test.go index b6d967ce7..2d2afadec 100644 --- a/pkg/solana/logpoller/worker_test.go +++ b/pkg/solana/logpoller/worker_test.go @@ -116,6 +116,8 @@ func TestWorkerGroup_Close(t *testing.T) { var mu sync.RWMutex output := make([]int, 10) + chContinue := make(chan struct{}, 1) + for idx := range output { _ = group.Do(ctx, testJob{job: func(ctx context.Context) error { mu.Lock() @@ -140,12 +142,18 @@ func TestWorkerGroup_Close(t *testing.T) { output[idx] = 1 + select { + case chContinue <- struct{}{}: + default: + } + return nil }}) } - // wait for the first 9 to finish and close the group - time.Sleep(100 * time.Millisecond) + // wait for at least one job to finish and close the group + tests.RequireSignal(t, chContinue, "timed out waiting for at least one job to complete") + group.Close() mu.RLock() From b2b090a7d851ac6fda518658f51624457fda10e2 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Thu, 7 Nov 2024 09:25:43 -0600 Subject: [PATCH 13/19] throw error if signatures and transactions don't match --- pkg/solana/logpoller/job.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/solana/logpoller/job.go b/pkg/solana/logpoller/job.go index 09b3aefa5..c090527a7 100644 --- a/pkg/solana/logpoller/job.go +++ b/pkg/solana/logpoller/job.go @@ -112,6 +112,10 @@ func (j *getTransactionsFromBlockJob) Run(ctx context.Context) error { detail.blockNumber = *block.BlockHeight } + if len(block.Transactions) != len(blockSigsOnly.Signatures) { + return fmt.Errorf("block %d has %d transactions but %d signatures", j.slotNumber, len(block.Transactions), len(blockSigsOnly.Signatures)) + } + for idx, trx := range block.Transactions { detail.trxIdx = idx if len(blockSigsOnly.Signatures)-1 <= idx { From 973aee0e4c033d925b67d3eb6c03ad9a37ddc83b Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Mon, 11 Nov 2024 09:03:00 -0600 Subject: [PATCH 14/19] minor update on if block --- pkg/solana/logpoller/loader.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pkg/solana/logpoller/loader.go b/pkg/solana/logpoller/loader.go index 4757f73c4..8b9444219 100644 --- a/pkg/solana/logpoller/loader.go +++ b/pkg/solana/logpoller/loader.go @@ -178,12 +178,14 @@ func (c *EncodedLogCollector) runSlotProcessing(ctx context.Context) { case <-ctx.Done(): return case slot := <-c.chSlot: - if c.highestSlot.Load() < slot { - c.highestSlot.Store(slot) - - // load blocks in slot range - c.loadRange(ctx, c.highestSlotLoaded.Load()+1, slot) + if c.highestSlot.Load() >= slot { + continue } + + c.highestSlot.Store(slot) + + // load blocks in slot range + c.loadRange(ctx, c.highestSlotLoaded.Load()+1, slot) } } } @@ -249,7 +251,10 @@ func (c *EncodedLogCollector) loadSlotBlocksRange(ctx context.Context, start, en } for _, block := range result { - c.chBlock <- block + select { + case <-ctx.Done(): + case c.chBlock <- block: + } } return nil From 561e68a8af9c1b22337f2afc3eca364d2b38021a Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Tue, 12 Nov 2024 10:09:07 -0600 Subject: [PATCH 15/19] add unit test for backfill --- pkg/solana/logpoller/loader_test.go | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/pkg/solana/logpoller/loader_test.go b/pkg/solana/logpoller/loader_test.go index 32defd97e..6b8c4743a 100644 --- a/pkg/solana/logpoller/loader_test.go +++ b/pkg/solana/logpoller/loader_test.go @@ -89,6 +89,57 @@ func TestEncodedLogCollector_ParseSingleEvent(t *testing.T) { client.AssertExpectations(t) } +func TestEncodedLogCollector_BackfillForAddress(t *testing.T) { + client := new(mocks.RPCClient) + parser := new(testParser) + ctx := tests.Context(t) + + collector := logpoller.NewEncodedLogCollector(client, parser, logger.Nop()) + + require.NoError(t, collector.Start(ctx)) + t.Cleanup(func() { + require.NoError(t, collector.Close()) + }) + + pubKey := solana.PublicKey{2, 1, 4, 2} + slots := []uint64{42, 43, 44} + blockHeights := []uint64{21, 22, 23} + sig := solana.Signature{2, 1, 4, 2} + + client.EXPECT().GetSignaturesForAddressWithOpts(mock.Anything, pubKey, mock.Anything).Return([]*rpc.TransactionSignature{ + {Slot: slots[0]}, + {Slot: slots[1]}, + {Slot: slots[2]}, + }, nil) + + for idx := range len(slots) { + client.EXPECT().GetBlockWithOpts(mock.Anything, slots[idx], mock.Anything).Return(&rpc.GetBlockResult{ + Transactions: []rpc.TransactionWithMeta{ + { + Meta: &rpc.TransactionMeta{ + LogMessages: messages, + }, + }, + { + Meta: &rpc.TransactionMeta{ + LogMessages: messages, + }, + }, + }, + Signatures: []solana.Signature{sig, sig}, + BlockHeight: &blockHeights[idx], + }, nil).Twice() + } + + assert.NoError(t, collector.BackfillForAddress(ctx, pubKey.String(), 42)) + + tests.AssertEventually(t, func() bool { + return parser.Count() == 6 + }) + + client.AssertExpectations(t) +} + func BenchmarkEncodedLogCollector(b *testing.B) { ctx := tests.Context(b) From 06146f7385860bf6469740973973c22b498679f5 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Tue, 12 Nov 2024 13:42:38 -0600 Subject: [PATCH 16/19] address comments --- pkg/solana/logpoller/loader.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/solana/logpoller/loader.go b/pkg/solana/logpoller/loader.go index 8b9444219..65e1cacfe 100644 --- a/pkg/solana/logpoller/loader.go +++ b/pkg/solana/logpoller/loader.go @@ -225,7 +225,7 @@ func (c *EncodedLogCollector) loadRange(ctx context.Context, start, end uint64) if err := c.loadSlotBlocksRange(ctx, start, end); err != nil { // a retry will happen anyway on the next round of slots // so the error is handled by doing nothing - c.lggr.Error("failed to load slot blocks range", "start", start, "end", end, "err", err) + c.lggr.Errorw("failed to load slot blocks range", "start", start, "end", end, "err", err) return } @@ -253,6 +253,7 @@ func (c *EncodedLogCollector) loadSlotBlocksRange(ctx context.Context, start, en for _, block := range result { select { case <-ctx.Done(): + return nil case c.chBlock <- block: } } From 8df7938bb998805087f085f25026f38900e66b57 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Thu, 14 Nov 2024 08:23:25 -0600 Subject: [PATCH 17/19] address minor comments --- pkg/solana/logpoller/job.go | 2 -- pkg/solana/logpoller/loader_test.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/solana/logpoller/job.go b/pkg/solana/logpoller/job.go index c090527a7..091f4bb57 100644 --- a/pkg/solana/logpoller/job.go +++ b/pkg/solana/logpoller/job.go @@ -73,7 +73,6 @@ func (j *getTransactionsFromBlockJob) Run(ctx context.Context) error { block, err := j.client.GetBlockWithOpts( ctx, j.slotNumber, - // You can specify more options here: &rpc.GetBlockOpts{ Encoding: solana.EncodingBase64, Commitment: rpc.CommitmentFinalized, @@ -90,7 +89,6 @@ func (j *getTransactionsFromBlockJob) Run(ctx context.Context) error { blockSigsOnly, err := j.client.GetBlockWithOpts( ctx, j.slotNumber, - // You can specify more options here: &rpc.GetBlockOpts{ Encoding: solana.EncodingBase64, Commitment: rpc.CommitmentFinalized, diff --git a/pkg/solana/logpoller/loader_test.go b/pkg/solana/logpoller/loader_test.go index 6b8c4743a..ee1d23a72 100644 --- a/pkg/solana/logpoller/loader_test.go +++ b/pkg/solana/logpoller/loader_test.go @@ -170,7 +170,7 @@ BenchLoop: case <-ticker.C: blockProducer.incrementSlot() case <-ctx.Done(): - continue BenchLoop + break BenchLoop default: blockProducer.makeEvent() } From dd552e32dc01640710d5649173ab15aa94b4b220 Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Fri, 15 Nov 2024 09:31:46 -0600 Subject: [PATCH 18/19] loop over multiple signatures for address --- pkg/solana/logpoller/loader.go | 63 ++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/pkg/solana/logpoller/loader.go b/pkg/solana/logpoller/loader.go index 65e1cacfe..000d5f140 100644 --- a/pkg/solana/logpoller/loader.go +++ b/pkg/solana/logpoller/loader.go @@ -90,29 +90,54 @@ func (c *EncodedLogCollector) BackfillForAddress(ctx context.Context, address st return err } - sigs, err := c.client.GetSignaturesForAddressWithOpts(ctx, pubKey, &rpc.GetSignaturesForAddressOpts{ - Commitment: rpc.CommitmentFinalized, - MinContextSlot: &fromSlot, - }) - if err != nil { - return err - } + var ( + lowestSlotRead uint64 + lowestSlotSig solana.Signature + ) - slots := make(map[uint64]struct{}) + for lowestSlotRead > fromSlot { + opts := rpc.GetSignaturesForAddressOpts{ + Commitment: rpc.CommitmentFinalized, + MinContextSlot: &fromSlot, + } - for _, sig := range sigs { - _, ok := slots[sig.Slot] - if !ok { - if err := c.workers.Do(ctx, &getTransactionsFromBlockJob{ - slotNumber: sig.Slot, - client: c.client, - parser: c.parser, - chJobs: c.chJobs, - }); err != nil { - return err + if lowestSlotRead > 0 { + opts.Before = lowestSlotSig + } + + sigs, err := c.client.GetSignaturesForAddressWithOpts(ctx, pubKey, &opts) + if err != nil { + return err + } + + slots := make(map[uint64]struct{}) + + var newSigsFound bool + + for _, sig := range sigs { + if sig.Slot < lowestSlotRead { + lowestSlotRead = sig.Slot + lowestSlotSig = sig.Signature } - slots[sig.Slot] = struct{}{} + _, ok := slots[sig.Slot] + if !ok { + if err := c.workers.Do(ctx, &getTransactionsFromBlockJob{ + slotNumber: sig.Slot, + client: c.client, + parser: c.parser, + chJobs: c.chJobs, + }); err != nil { + return err + } + + slots[sig.Slot] = struct{}{} + newSigsFound = true + } + } + + if !newSigsFound { + break } } From 982487b31a10842df12eff6c124aedad57d1509b Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Fri, 15 Nov 2024 10:33:01 -0600 Subject: [PATCH 19/19] make test pass --- pkg/solana/logpoller/loader.go | 4 ++-- pkg/solana/logpoller/loader_test.go | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/pkg/solana/logpoller/loader.go b/pkg/solana/logpoller/loader.go index 000d5f140..ea22a0655 100644 --- a/pkg/solana/logpoller/loader.go +++ b/pkg/solana/logpoller/loader.go @@ -95,7 +95,7 @@ func (c *EncodedLogCollector) BackfillForAddress(ctx context.Context, address st lowestSlotSig solana.Signature ) - for lowestSlotRead > fromSlot { + for lowestSlotRead > fromSlot || lowestSlotRead == 0 { opts := rpc.GetSignaturesForAddressOpts{ Commitment: rpc.CommitmentFinalized, MinContextSlot: &fromSlot, @@ -115,7 +115,7 @@ func (c *EncodedLogCollector) BackfillForAddress(ctx context.Context, address st var newSigsFound bool for _, sig := range sigs { - if sig.Slot < lowestSlotRead { + if sig.Slot < lowestSlotRead || lowestSlotRead == 0 { lowestSlotRead = sig.Slot lowestSlotSig = sig.Signature } diff --git a/pkg/solana/logpoller/loader_test.go b/pkg/solana/logpoller/loader_test.go index ee1d23a72..7c8c5dcfb 100644 --- a/pkg/solana/logpoller/loader_test.go +++ b/pkg/solana/logpoller/loader_test.go @@ -2,7 +2,7 @@ package logpoller_test import ( "context" - "math/rand/v2" + "crypto/rand" "sync" "sync/atomic" "testing" @@ -103,8 +103,7 @@ func TestEncodedLogCollector_BackfillForAddress(t *testing.T) { pubKey := solana.PublicKey{2, 1, 4, 2} slots := []uint64{42, 43, 44} - blockHeights := []uint64{21, 22, 23} - sig := solana.Signature{2, 1, 4, 2} + blockHeights := []uint64{21, 22, 23, 50} client.EXPECT().GetSignaturesForAddressWithOpts(mock.Anything, pubKey, mock.Anything).Return([]*rpc.TransactionSignature{ {Slot: slots[0]}, @@ -113,6 +112,14 @@ func TestEncodedLogCollector_BackfillForAddress(t *testing.T) { }, nil) for idx := range len(slots) { + var ( + sig1 solana.Signature + sig2 solana.Signature + ) + + _, _ = rand.Read(sig1[:]) + _, _ = rand.Read(sig2[:]) + client.EXPECT().GetBlockWithOpts(mock.Anything, slots[idx], mock.Anything).Return(&rpc.GetBlockResult{ Transactions: []rpc.TransactionWithMeta{ { @@ -126,7 +133,7 @@ func TestEncodedLogCollector_BackfillForAddress(t *testing.T) { }, }, }, - Signatures: []solana.Signature{sig, sig}, + Signatures: []solana.Signature{sig1, sig2}, BlockHeight: &blockHeights[idx], }, nil).Twice() } @@ -206,7 +213,9 @@ func (p *testBlockProducer) makeEvent() { p.mu.Lock() defer p.mu.Unlock() - sig := solana.Signature{byte(rand.Int64())} + var sig solana.Signature + + _, _ = rand.Read(sig[:]) p.blockSigs[p.nextSlot] = append(p.blockSigs[p.nextSlot], sig) p.sigs[sig.String()] = true