diff --git a/contracts/generated/contract_reader_interface/Initialize.go b/contracts/generated/contract_reader_interface/Initialize.go index f5693861a..5f9f3831d 100644 --- a/contracts/generated/contract_reader_interface/Initialize.go +++ b/contracts/generated/contract_reader_interface/Initialize.go @@ -19,22 +19,14 @@ type Initialize struct { // // [1] = [WRITE] data // - // [2] = [WRITE] multiRead1 - // - // [3] = [WRITE] multiRead2 - // - // [4] = [WRITE] configWrapperAccount1 - // - // [5] = [WRITE] configWrapperAccount2 - // - // [6] = [] systemProgram + // [2] = [] systemProgram ag_solanago.AccountMetaSlice `bin:"-"` } // NewInitializeInstructionBuilder creates a new `Initialize` instruction builder. func NewInitializeInstructionBuilder() *Initialize { nd := &Initialize{ - AccountMetaSlice: make(ag_solanago.AccountMetaSlice, 7), + AccountMetaSlice: make(ag_solanago.AccountMetaSlice, 3), } return nd } @@ -73,59 +65,15 @@ func (inst *Initialize) GetDataAccount() *ag_solanago.AccountMeta { return inst.AccountMetaSlice.Get(1) } -// SetMultiRead1Account sets the "multiRead1" account. -func (inst *Initialize) SetMultiRead1Account(multiRead1 ag_solanago.PublicKey) *Initialize { - inst.AccountMetaSlice[2] = ag_solanago.Meta(multiRead1).WRITE() - return inst -} - -// GetMultiRead1Account gets the "multiRead1" account. -func (inst *Initialize) GetMultiRead1Account() *ag_solanago.AccountMeta { - return inst.AccountMetaSlice.Get(2) -} - -// SetMultiRead2Account sets the "multiRead2" account. -func (inst *Initialize) SetMultiRead2Account(multiRead2 ag_solanago.PublicKey) *Initialize { - inst.AccountMetaSlice[3] = ag_solanago.Meta(multiRead2).WRITE() - return inst -} - -// GetMultiRead2Account gets the "multiRead2" account. -func (inst *Initialize) GetMultiRead2Account() *ag_solanago.AccountMeta { - return inst.AccountMetaSlice.Get(3) -} - -// SetConfigWrapperAccount1Account sets the "configWrapperAccount1" account. -func (inst *Initialize) SetConfigWrapperAccount1Account(configWrapperAccount1 ag_solanago.PublicKey) *Initialize { - inst.AccountMetaSlice[4] = ag_solanago.Meta(configWrapperAccount1).WRITE() - return inst -} - -// GetConfigWrapperAccount1Account gets the "configWrapperAccount1" account. -func (inst *Initialize) GetConfigWrapperAccount1Account() *ag_solanago.AccountMeta { - return inst.AccountMetaSlice.Get(4) -} - -// SetConfigWrapperAccount2Account sets the "configWrapperAccount2" account. -func (inst *Initialize) SetConfigWrapperAccount2Account(configWrapperAccount2 ag_solanago.PublicKey) *Initialize { - inst.AccountMetaSlice[5] = ag_solanago.Meta(configWrapperAccount2).WRITE() - return inst -} - -// GetConfigWrapperAccount2Account gets the "configWrapperAccount2" account. -func (inst *Initialize) GetConfigWrapperAccount2Account() *ag_solanago.AccountMeta { - return inst.AccountMetaSlice.Get(5) -} - // SetSystemProgramAccount sets the "systemProgram" account. func (inst *Initialize) SetSystemProgramAccount(systemProgram ag_solanago.PublicKey) *Initialize { - inst.AccountMetaSlice[6] = ag_solanago.Meta(systemProgram) + inst.AccountMetaSlice[2] = ag_solanago.Meta(systemProgram) return inst } // GetSystemProgramAccount gets the "systemProgram" account. func (inst *Initialize) GetSystemProgramAccount() *ag_solanago.AccountMeta { - return inst.AccountMetaSlice.Get(6) + return inst.AccountMetaSlice.Get(2) } func (inst Initialize) Build() *Instruction { @@ -165,18 +113,6 @@ func (inst *Initialize) Validate() error { return errors.New("accounts.Data is not set") } if inst.AccountMetaSlice[2] == nil { - return errors.New("accounts.MultiRead1 is not set") - } - if inst.AccountMetaSlice[3] == nil { - return errors.New("accounts.MultiRead2 is not set") - } - if inst.AccountMetaSlice[4] == nil { - return errors.New("accounts.ConfigWrapperAccount1 is not set") - } - if inst.AccountMetaSlice[5] == nil { - return errors.New("accounts.ConfigWrapperAccount2 is not set") - } - if inst.AccountMetaSlice[6] == nil { return errors.New("accounts.SystemProgram is not set") } } @@ -198,14 +134,10 @@ func (inst *Initialize) EncodeToTree(parent ag_treeout.Branches) { }) // Accounts of the instruction: - instructionBranch.Child("Accounts[len=7]").ParentFunc(func(accountsBranch ag_treeout.Branches) { - accountsBranch.Child(ag_format.Meta(" signer", inst.AccountMetaSlice.Get(0))) - accountsBranch.Child(ag_format.Meta(" data", inst.AccountMetaSlice.Get(1))) - accountsBranch.Child(ag_format.Meta(" multiRead1", inst.AccountMetaSlice.Get(2))) - accountsBranch.Child(ag_format.Meta(" multiRead2", inst.AccountMetaSlice.Get(3))) - accountsBranch.Child(ag_format.Meta("configWrapperAccount1", inst.AccountMetaSlice.Get(4))) - accountsBranch.Child(ag_format.Meta("configWrapperAccount2", inst.AccountMetaSlice.Get(5))) - accountsBranch.Child(ag_format.Meta(" systemProgram", inst.AccountMetaSlice.Get(6))) + instructionBranch.Child("Accounts[len=3]").ParentFunc(func(accountsBranch ag_treeout.Branches) { + accountsBranch.Child(ag_format.Meta(" signer", inst.AccountMetaSlice.Get(0))) + accountsBranch.Child(ag_format.Meta(" data", inst.AccountMetaSlice.Get(1))) + accountsBranch.Child(ag_format.Meta("systemProgram", inst.AccountMetaSlice.Get(2))) }) }) }) @@ -246,19 +178,11 @@ func NewInitializeInstruction( // Accounts: signer ag_solanago.PublicKey, data ag_solanago.PublicKey, - multiRead1 ag_solanago.PublicKey, - multiRead2 ag_solanago.PublicKey, - configWrapperAccount1 ag_solanago.PublicKey, - configWrapperAccount2 ag_solanago.PublicKey, systemProgram ag_solanago.PublicKey) *Initialize { return NewInitializeInstructionBuilder(). SetTestIdx(testIdx). SetValue(value). SetSignerAccount(signer). SetDataAccount(data). - SetMultiRead1Account(multiRead1). - SetMultiRead2Account(multiRead2). - SetConfigWrapperAccount1Account(configWrapperAccount1). - SetConfigWrapperAccount2Account(configWrapperAccount2). SetSystemProgramAccount(systemProgram) } diff --git a/contracts/generated/contract_reader_interface/instructions.go b/contracts/generated/contract_reader_interface/instructions.go index f4b7f964c..a89942e9c 100644 --- a/contracts/generated/contract_reader_interface/instructions.go +++ b/contracts/generated/contract_reader_interface/instructions.go @@ -30,6 +30,8 @@ func init() { var ( Instruction_Initialize = ag_binary.TypeID([8]byte{175, 175, 109, 31, 13, 152, 155, 237}) + Instruction_InitializeOnce = ag_binary.TypeID([8]byte{36, 138, 127, 107, 36, 120, 55, 138}) + Instruction_InitializeLookupTable = ag_binary.TypeID([8]byte{149, 120, 10, 249, 212, 185, 177, 216}) Instruction_Store = ag_binary.TypeID([8]byte{220, 28, 207, 235, 0, 234, 193, 246}) @@ -40,6 +42,8 @@ func InstructionIDToName(id ag_binary.TypeID) string { switch id { case Instruction_Initialize: return "Initialize" + case Instruction_InitializeOnce: + return "InitializeOnce" case Instruction_InitializeLookupTable: return "InitializeLookupTable" case Instruction_Store: @@ -67,6 +71,9 @@ var InstructionImplDef = ag_binary.NewVariantDefinition( { "initialize", (*Initialize)(nil), }, + { + "initialize_once", (*InitializeOnce)(nil), + }, { "initialize_lookup_table", (*InitializeLookupTable)(nil), }, diff --git a/contracts/programs/contract-reader-interface/src/lib.rs b/contracts/programs/contract-reader-interface/src/lib.rs index 058b56406..49a7a2173 100644 --- a/contracts/programs/contract-reader-interface/src/lib.rs +++ b/contracts/programs/contract-reader-interface/src/lib.rs @@ -1,6 +1,6 @@ use anchor_lang::prelude::*; -use std::mem::size_of; use solana_program::pubkey; +use std::mem::size_of; declare_id!("6AfuXF6HapDUhQfE4nQG9C1SGtA1YjP3icaJyRfU4RyE"); @@ -15,6 +15,10 @@ pub mod contract_reader_interface { account.idx = test_idx; account.bump = ctx.bumps.data; + Ok(()) + } + + pub fn initializeOnce(ctx: Context) -> Result<()> { let multi_read1 = &mut ctx.accounts.multi_read1; multi_read1.a = 1; multi_read1.b = 2; @@ -24,13 +28,13 @@ pub mod contract_reader_interface { multi_read2.u = "Hello".to_string(); multi_read2.v = true; multi_read2.w = [123, 456]; - + let config1 = &mut ctx.accounts.config_wrapper_account1; config1.config.usd_per_token = TimestampedPackedU224 { value: STATIC_VALUE1, timestamp: STATIC_TIMESTAMP1, }; - + let config2 = &mut ctx.accounts.config_wrapper_account2; config2.config.usd_per_token = TimestampedPackedU224 { value: STATIC_VALUE2, @@ -88,6 +92,14 @@ pub struct Initialize<'info> { bump)] pub data: Account<'info, DataAccount>, + pub system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct InitializeOnce<'info> { + #[account(mut)] + pub signer: Signer<'info>, + #[account( init_if_needed, payer = signer, @@ -103,29 +115,27 @@ pub struct Initialize<'info> { seeds = [b"multi_read2"], bump)] pub multi_read2: Account<'info, MultiRead2>, - + #[account( init_if_needed, payer = signer, - space = 8 + size_of::(), + space = size_of::() + 8, seeds = [ b"fee_billing_token_config", ADDRESS_1.as_ref() ], - bump - )] + bump)] pub config_wrapper_account1: Account<'info, BillingTokenConfigWrapper>, #[account( init_if_needed, payer = signer, - space = 8 + size_of::(), + space = size_of::() + 8, seeds = [ b"fee_billing_token_config", ADDRESS_2.as_ref() ], - bump - )] + bump)] pub config_wrapper_account2: Account<'info, BillingTokenConfigWrapper>, pub system_program: Program<'info, System>, @@ -279,24 +289,14 @@ pub const ADDRESS_1: Pubkey = pubkey!("4RzYhbqRjaZHMnfxiPNDVzuimBbAb2FZErQKCLYKr pub const ADDRESS_2: Pubkey = pubkey!("9mBYSvyF8RBWNdat6SkZE5ipW5gMrBYqZnTShMsnfsub"); pub const STATIC_VALUE1: [u8; 28] = [ - 0x00, 0x11, 0x22, 0x33, - 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xAA, 0xBB, - 0xCC, 0xDD, 0xEE, 0xFF, - 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, ]; -pub const STATIC_TIMESTAMP1: i64 = 1_700_000_001; +pub const STATIC_TIMESTAMP1: i64 = 1_700_000_001; pub const STATIC_VALUE2: [u8; 28] = [ - 0xAA, 0xBB, 0xCC, 0xDD, - 0xEE, 0xFF, 0x11, 0x22, - 0x33, 0x44, 0x55, 0x66, - 0x77, 0x88, 0x99, 0x00, - 0x10, 0x20, 0x30, 0x40, - 0x50, 0x60, 0x70, 0x80, - 0x90, 0xA0, 0xB0, 0xC0 + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, + 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, ]; pub const STATIC_TIMESTAMP2: i64 = 1_800_000_002; @@ -319,5 +319,5 @@ pub struct BillingTokenConfig { #[derive(InitSpace, Clone, AnchorSerialize, AnchorDeserialize, Debug)] pub struct TimestampedPackedU224 { pub value: [u8; 28], - pub timestamp: i64, + pub timestamp: i64, } diff --git a/integration-tests/relayinterface/chain_components_test.go b/integration-tests/relayinterface/chain_components_test.go index ab13caa34..4761b916f 100644 --- a/integration-tests/relayinterface/chain_components_test.go +++ b/integration-tests/relayinterface/chain_components_test.go @@ -55,11 +55,11 @@ const ( func TestChainComponents(t *testing.T) { t.Parallel() - helper := &helper{} - helper.Init(t) t.Run("RunChainComponentsSolanaTests", func(t *testing.T) { t.Parallel() + helper := &helper{} + helper.Init(t) it := &SolanaChainComponentsInterfaceTester[*testing.T]{Helper: helper, testContext: make(map[string]uint64), testContextMu: &sync.RWMutex{}, testIdx: &atomic.Uint64{}} DisableTests(it) it.Setup(t) @@ -68,6 +68,8 @@ func TestChainComponents(t *testing.T) { t.Run("RunChainComponentsInLoopSolanaTests", func(t *testing.T) { t.Parallel() + helper := &helper{} + helper.Init(t) it := &SolanaChainComponentsInterfaceTester[*testing.T]{Helper: helper, testContext: make(map[string]uint64), testContextMu: &sync.RWMutex{}, testIdx: &atomic.Uint64{}} DisableTests(it) wrapped := commontestutils.WrapContractReaderTesterForLoop(it) @@ -197,8 +199,8 @@ func RunContractReaderTests[T WrappedTestingT[T]](t T, it *SolanaChainComponents // GetLatestValue method const ( - ContractReaderGetLatestValueUsingMultiReader = "Get latest value using multi reader" - ContractReaderGetLatestValueUsingSplitParamsReader = "Get latest value using split params reader" + ContractReaderGetLatestValueUsingMultiReader = "Get latest value using multi reader" + ContractReaderGetLatestValueGetTokenPrices = "Get latest value handles get token prices edge case" ) type TimestampedUnixBig struct { @@ -235,7 +237,7 @@ func RunContractReaderInLoopTests[T WrappedTestingT[T]](t T, it ChainComponentsI }, }, { - Name: ContractReaderGetLatestValueUsingSplitParamsReader, + Name: ContractReaderGetLatestValueGetTokenPrices, Test: func(t T) { cr := it.GetContractReader(t) bindings := it.GetBindings(t) @@ -253,9 +255,9 @@ func RunContractReaderInLoopTests[T WrappedTestingT[T]](t T, it ChainComponentsI res := make([]TimestampedUnixBig, 2) byteTokens := make([][]byte, 0, 2) - pubKey1, err := solana.PublicKeyFromBase58(SplitParamPubKey1) + pubKey1, err := solana.PublicKeyFromBase58(GetTokenPricesPubKey1) require.NoError(t, err) - pubKey2, err := solana.PublicKeyFromBase58(SplitParamPubKey2) + pubKey2, err := solana.PublicKeyFromBase58(GetTokenPricesPubKey2) require.NoError(t, err) byteTokens = append(byteTokens, pubKey1.Bytes()) @@ -395,6 +397,7 @@ func (it *SolanaChainComponentsInterfaceTester[T]) GenerateBlocksTillConfidenceL } type helper struct { + initOnce sync.Once primaryProgramID solana.PublicKey secondaryProgramID solana.PublicKey rpcURL string @@ -560,16 +563,26 @@ func (h *helper) runInitialize( return } + fmt.Println("testIdx:") + for k, v := range it.testContext { + fmt.Println("k:", k, "v:", v) + } + initArgs := InitializeArgs{ TestIdx: testIdx, Value: value, } SubmitTransactionToCW(t, &it, cw, "initialize", initArgs, types.BoundContract{Name: contractName, Address: programID.String()}, types.Finalized) + h.initOnce.Do(func() { + SubmitTransactionToCW(t, &it, cw, "initializeOnce", nil, types.BoundContract{Name: contractName, Address: programID.String()}, types.Finalized) + }) + storeStructArgs := StoreStructArgs{ TestIdx: testIdx, Data: testStruct, } + fmt.Println("storeStructArgs", storeStructArgs) SubmitTransactionToCW(t, &it, cw, MethodSettingStruct, storeStructArgs, types.BoundContract{Name: contractName, Address: programID.String()}, types.Finalized) } @@ -639,7 +652,11 @@ func (it *SolanaChainComponentsInterfaceTester[T]) buildContractReaderConfig(t T PDADefinition: codec.PDATypeDef{ Prefix: []byte("multi_read1"), }, - OutputModifications: commoncodec.ModifiersConfig{}, + OutputModifications: commoncodec.ModifiersConfig{ + &commoncodec.HardCodeModifierConfig{ + OffChainValues: map[string]any{"U": "", "V": false}, + }, + }, MultiReader: &config.MultiReader{Reads: []config.ReadDefinition{ { ChainSpecificName: "MultiRead2", @@ -740,8 +757,8 @@ func (it *SolanaChainComponentsInterfaceTester[T]) buildContractReaderConfig(t T } const ( - SplitParamPubKey1 = "4RzYhbqRjaZHMnfxiPNDVzuimBbAb2FZErQKCLYKrkMe" - SplitParamPubKey2 = "9mBYSvyF8RBWNdat6SkZE5ipW5gMrBYqZnTShMsnfsub" + GetTokenPricesPubKey1 = "4RzYhbqRjaZHMnfxiPNDVzuimBbAb2FZErQKCLYKrkMe" + GetTokenPricesPubKey2 = "9mBYSvyF8RBWNdat6SkZE5ipW5gMrBYqZnTShMsnfsub" ) func (it *SolanaChainComponentsInterfaceTester[T]) buildContractWriterConfig(t T) chainwriter.ChainWriterConfig { @@ -749,9 +766,9 @@ func (it *SolanaChainComponentsInterfaceTester[T]) buildContractWriterConfig(t T testIdx := binary.LittleEndian.AppendUint64([]byte{}, idx) fromAddress := solana.MustPrivateKeyFromBase58(solclient.DefaultPrivateKeysSolValidator[1]).PublicKey().String() testStruct := CreateTestStruct(0, it) - pubKey1, err := solana.PublicKeyFromBase58(SplitParamPubKey1) + pubKey1, err := solana.PublicKeyFromBase58(GetTokenPricesPubKey1) require.NoError(t, err) - pubKey2, err := solana.PublicKeyFromBase58(SplitParamPubKey2) + pubKey2, err := solana.PublicKeyFromBase58(GetTokenPricesPubKey2) require.NoError(t, err) return chainwriter.ChainWriterConfig{ @@ -783,6 +800,27 @@ func (it *SolanaChainComponentsInterfaceTester[T]) buildContractWriterConfig(t T IsWritable: true, IsSigner: false, }, + chainwriter.AccountConstant{ + Name: "SystemProgram", + Address: solana.SystemProgramID.String(), + IsWritable: false, + IsSigner: false, + }, + }, + DebugIDLocation: "", + }, + "initializeOnce": { + FromAddress: fromAddress, + InputModifications: nil, + ChainSpecificName: "initializeOnce", + LookupTables: chainwriter.LookupTables{}, + Accounts: []chainwriter.Lookup{ + chainwriter.AccountConstant{ + Name: "Signer", + Address: fromAddress, + IsSigner: true, + IsWritable: true, + }, chainwriter.PDALookups{ Name: "MultiRead1", PublicKey: chainwriter.AccountConstant{ diff --git a/pkg/solana/chainreader/chain_reader.go b/pkg/solana/chainreader/chain_reader.go index 597921c3b..f41dd38cf 100644 --- a/pkg/solana/chainreader/chain_reader.go +++ b/pkg/solana/chainreader/chain_reader.go @@ -168,6 +168,10 @@ func (s *ContractReaderService) GetLatestValue(ctx context.Context, readIdentifi return doMultiRead(ctx, s.client, s.bdRegistry, values, returnVal) } + if values.multiRead[0] == "GetTokenPrices" { + return s.handleGetTokenPricesGetLatestValue(ctx, params, values, returnVal) + } + batch := []call{ { Namespace: values.contract, @@ -177,10 +181,6 @@ func (s *ContractReaderService) GetLatestValue(ctx context.Context, readIdentifi }, } - if values.multiRead[0] == "GetTokenPrices" { - return s.handleGetTokenPricesGetLatestValue(ctx, params, values, returnVal) - } - results, err := doMethodBatchCall(ctx, s.client, s.bdRegistry, batch) if err != nil { return err