soonlabs / igloo

Demo for op rollup with decoupling SVM execution layer
MIT License
27 stars 6 forks source link

feat: igloo HTTP JsonRPC Framework #25

Closed ghost closed 1 month ago

ghost commented 2 months ago

HTTP Methods - explorer

Account Info

Transaction History

Transaction

Block Info

Slot Info

Token Info

Cluster Info

Environment Info

Monitoring

ghost commented 2 months ago

Stub methods for retrieving Account Info, Transaction History, Block Info, and Slot Info

block generation

We can assume that Transactions are executed in batches, with the first batch having both Slot and Block set to 0, and each subsequent batch incrementing these values

ref: https://github.com/soonlabs/igloo/issues/22 Implement a Robust Standard Transaction Executor Batch Transaction Processing: Enable execution of multiple transactions simultaneously Automated Block Height Management

Accounts Info

Obtained from BankWrapper and Bank

Transaction History

Igloo needs to implement write_transaction_status_batch, assemble EncodedTransactionWithStatusMeta and write it to Blockstore (Rocksdb)

ghost commented 2 months ago

Assemble EncodedTransactionWithStatusMeta

A JSON format response for a transaction, transferring SOL from Alice to Bob

{
  "slot": 279956924,
  "transaction": {
    "transaction": {
      "signatures": [
        "5LSMipi9UFCJnMMJUYDCJKMtW5io9rJvxkxJxFcTHr9AmC3wgTGAUe571ebsGu6tWstzhyrZDRUnqBhSe4mVMuvP"
      ],
      "message": {
        "header": {
          "num_required_signatures": 1,
          "num_readonly_signed_accounts": 0,
          "num_readonly_unsigned_accounts": 1
        },
        "account_keys": [
          "5K4KLyoqBwS58sWjuJvhnuu794us4XGjTcXSTDUjwmJ2",
          "93Mto7Rdgs5anS1QeqHCrynxoSzmEeBaxb4V8QGfZSvH",
          "11111111111111111111111111111111"
        ],
        "recent_blockhash": "5w1hduKLySSDpL4sZWxZREAxz14DeEF2xSMJVbjEVD8x",
        "instructions": [
          {
            "program_id_index": 2,
            "accounts": [0, 1],
            "data": "3Bxs3zzLZLuLQEYX",
            "stack_height": null
          }
        ],
        "address_table_lookups": null
      }
    },
    "meta": {
      "err": null,
      "status": "Ok(())",
      "fee": 5000,
      "pre_balances": [156656299827848, 0, 1],
      "post_balances": [156655299822848, 1000000000, 1],
      "inner_instructions": [],
      "log_messages": [
        "Program 11111111111111111111111111111111 invoke [1]",
        "Program 11111111111111111111111111111111 success"
      ],
      "pre_token_balances": [],
      "post_token_balances": [],
      "rewards": [],
      "loaded_addresses": {
        "writable": [],
        "readonly": []
      },
      "return_data": "Skip",
      "compute_units_consumed": 150
    },
    "version": null
  },
  "block_time": 1719676730
}

EncodedTransactionWithStatusMeta is a struct containing transaction status metadata, which includes information about the transaction's signature, message, status, and metadata.

UiTransactionStatusMeta is the type of the meta field in EncodedTransactionWithStatusMeta, and it contains metadata about the transaction status, such as the number of confirmations, execution time, and execution result of the transaction.

In simple terms, EncodedTransactionWithStatusMeta is a complete transaction status struct, while UiTransactionStatusMeta is a part of it that contains the metadata of the transaction status.

Where the banks-server outputs the transaction result

banks-server/src/banks_server.rs

async fn process_transaction_with_metadata_and_context(
    self,
    _: Context,
    transaction: VersionedTransaction,
) -> BanksTransactionResultWithMetadata {
    let bank = self.bank_forks.read().unwrap().working_bank();
    match bank.process_transaction_with_metadata(transaction) {
        Err(error) => BanksTransactionResultWithMetadata {
            result: Err(error),
            metadata: None,
        },
        Ok(details) => BanksTransactionResultWithMetadata {
            result: details.status,
            metadata: Some(TransactionMetadata {
                compute_units_consumed: details.executed_units,
                log_messages: details.log_messages.unwrap_or_default(),
                return_data: details.return_data,
            }),
        },
    }
}

TransactionExecutionDetails

&r0 = Executed {
    details: TransactionExecutionDetails {
        status: Ok(
            (),
        ),
        log_messages: None,
        inner_instructions: None,
        fee_details: FeeDetails {
            transaction_fee: 5000,
            prioritization_fee: 0,
            remove_rounding_in_fee_calculation: true,
        },
        return_data: None,
        executed_units: 150,
        accounts_data_len_delta: 0,
    },
    programs_modified_by_tx: {},
}

TransactionLoadResult

LoadedTransaction {
        accounts: [
            (
                AvfAPtoCuo8jCC73X9DQyGBTFEMH7t2p2cXqKLonJwz,
                Account {
                    lamports: 7995000,
                    data.len: 0,
                    owner: 11111111111111111111111111111111,
                    executable: false,
                    rent_epoch: 18446744073709551615,
                },
            ),
            (
                9Z7dtxs9HLTkMovQ1FW3ZL7q8JxQuEo3NHuZmR5Pwsjr,
                Account {
                    lamports: 12000000,
                    data.len: 0,
                    owner: 11111111111111111111111111111111,
                    executable: false,
                    rent_epoch: 18446744073709551615,
                },
            ),
            (
                11111111111111111111111111111111,
                Account {
                    lamports: 0,
                    data.len: 0,
                    owner: NativeLoader1111111111111111111111111111111,
                    executable: true,
                    rent_epoch: 0,
                },
            ),
        ],
        program_indices: [
            [
                2,
            ],
        ],
        fee_details: FeeDetails {
            transaction_fee: 5000,
            prioritization_fee: 0,
            remove_rounding_in_fee_calculation: true,
        },
        rollback_accounts: FeePayerOnly {
            fee_payer_account: Account {
                lamports: 9995000,
                data.len: 0,
                owner: 11111111111111111111111111111111,
                executable: false,
                rent_epoch: 0,
            },
        },
        compute_budget_limits: ComputeBudgetLimits {
            updated_heap_bytes: 32768,
            compute_unit_limit: 200000,
            compute_unit_price: 0,
            loaded_accounts_bytes: 67108864,
        },
        rent: 0,
        rent_debits: RentDebits(
            {},
        ),
        loaded_accounts_data_size: 14,
    }

~/solana/agave/svm/src/account_loader.rs

#[derive(PartialEq, Eq, Debug)]
pub enum TransactionLoadResult {
    /// All transaction accounts were loaded successfully
    Loaded(LoadedTransaction),
    /// Some transaction accounts needed for execution were unable to be loaded
    /// but the fee payer and any nonce account needed for fee collection were
    /// loaded successfully
    FeesOnly(FeesOnlyTransaction),
    /// Some transaction accounts needed for fee collection were unable to be
    /// loaded
    NotLoaded(TransactionError),
}
#[derive(PartialEq, Eq, Debug, Clone)]
#[cfg_attr(feature = "dev-context-only-utils", derive(Default))]
pub struct LoadedTransaction {
    pub accounts: Vec<TransactionAccount>,
    pub program_indices: TransactionProgramIndices,
    pub fee_details: FeeDetails,
    pub rollback_accounts: RollbackAccounts,
    pub compute_budget_limits: ComputeBudgetLimits,
    pub rent: TransactionRent,
    pub rent_debits: RentDebits,
    pub loaded_accounts_data_size: u32,
}

TransactionAccount: solana_sdk::transaction_context

TransactionProgramIndices: Vec<Vec<IndexOfAccount>>solana_sdk::transaction_context::IndexOfAccount

fee_details: solana_sdk::fee::FeeDetails

rollback_accounts: solana_sdk::account::AccountSharedData

compute_budget_limits: solana_compute_budget::compute_budget_processor::ComputeBudgetLimits

rent: u64

rent_debits:solana_sdk::rent_debits::RentDebits


Solana RPC returns EncodedConfirmedTransactionWithStatusMeta based on the Signature, which contains UiTransaction and UiTransactionStatusMeta

The SVM has split UiTransactionStatusMeta into TransactionExecutionResult and TransactionResults

What we need to do is reassemble the structures that SVM has split back into EncodedTransactionWithStatusMeta

ghost commented 2 months ago

For the json-rpc server part, keep the types as compatible as possible with Solana's raw types Just rewrite to keep code simple and easy to read.