From 31de8f553d8ce9f60481e3ca60079a4fb60ea845 Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Mon, 11 Apr 2022 10:50:17 +0800 Subject: [PATCH 01/19] feat(chain): init arweave from near --- Cargo.lock | 20 + chain/arweave/Cargo.toml | 25 + chain/arweave/build.rs | 8 + chain/arweave/proto/codec.proto | 521 +++++++++++ chain/arweave/src/adapter.rs | 204 +++++ chain/arweave/src/capabilities.rs | 37 + chain/arweave/src/chain.rs | 508 +++++++++++ chain/arweave/src/codec.rs | 109 +++ chain/arweave/src/data_source.rs | 403 +++++++++ chain/arweave/src/lib.rs | 11 + .../arweave/src/protobuf/sf.near.codec.v1.rs | 848 ++++++++++++++++++ chain/arweave/src/runtime/abi.rs | 637 +++++++++++++ chain/arweave/src/runtime/generated.rs | 620 +++++++++++++ chain/arweave/src/runtime/mod.rs | 6 + chain/arweave/src/runtime/runtime_adapter.rs | 11 + chain/arweave/src/trigger.rs | 498 ++++++++++ node/Cargo.toml | 1 + 17 files changed, 4467 insertions(+) create mode 100644 chain/arweave/Cargo.toml create mode 100644 chain/arweave/build.rs create mode 100644 chain/arweave/proto/codec.proto create mode 100644 chain/arweave/src/adapter.rs create mode 100644 chain/arweave/src/capabilities.rs create mode 100644 chain/arweave/src/chain.rs create mode 100644 chain/arweave/src/codec.rs create mode 100644 chain/arweave/src/data_source.rs create mode 100644 chain/arweave/src/lib.rs create mode 100644 chain/arweave/src/protobuf/sf.near.codec.v1.rs create mode 100644 chain/arweave/src/runtime/abi.rs create mode 100644 chain/arweave/src/runtime/generated.rs create mode 100644 chain/arweave/src/runtime/mod.rs create mode 100644 chain/arweave/src/runtime/runtime_adapter.rs create mode 100644 chain/arweave/src/trigger.rs diff --git a/Cargo.lock b/Cargo.lock index 3ca5e6ab57d..2974e811c9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1397,6 +1397,25 @@ dependencies = [ "web3", ] +[[package]] +name = "graph-chain-arweave" +version = "0.26.0" +dependencies = [ + "base64", + "diesel", + "graph", + "graph-core", + "graph-runtime-derive", + "graph-runtime-wasm", + "graph-store-postgres", + "pretty_assertions 0.7.2", + "prost", + "prost-types", + "serde", + "test-store", + "tonic-build", +] + [[package]] name = "graph-chain-ethereum" version = "0.26.0" @@ -1535,6 +1554,7 @@ dependencies = [ "futures 0.3.16", "git-testament", "graph", + "graph-chain-arweave", "graph-chain-ethereum", "graph-chain-near", "graph-chain-tendermint", diff --git a/chain/arweave/Cargo.toml b/chain/arweave/Cargo.toml new file mode 100644 index 00000000000..e4170d0670b --- /dev/null +++ b/chain/arweave/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "graph-chain-arweave" +version = "0.26.0" +edition = "2021" + +[build-dependencies] +tonic-build = "0.5.1" + +[dependencies] +base64 = "0.13" +graph = { path = "../../graph" } +prost = "0.8.0" +prost-types = "0.8.0" +serde = "1.0" + +graph-runtime-wasm = { path = "../../runtime/wasm" } +graph-runtime-derive = { path = "../../runtime/derive" } + +[dev-dependencies] +diesel = { version = "1.4.7", features = ["postgres", "serde_json", "numeric", "r2d2"] } +graph-core = { path = "../../core" } +graph-store-postgres = { path = "../../store/postgres" } +pretty_assertions = "0.7.2" +test-store = { path = "../../store/test-store" } + diff --git a/chain/arweave/build.rs b/chain/arweave/build.rs new file mode 100644 index 00000000000..435a5a3faa2 --- /dev/null +++ b/chain/arweave/build.rs @@ -0,0 +1,8 @@ +fn main() { + println!("cargo:rerun-if-changed=proto"); + tonic_build::configure() + .out_dir("src/protobuf") + .format(true) + .compile(&["proto/codec.proto"], &["proto"]) + .expect("Failed to compile Firehose NEAR proto(s)"); +} diff --git a/chain/arweave/proto/codec.proto b/chain/arweave/proto/codec.proto new file mode 100644 index 00000000000..22a0267669a --- /dev/null +++ b/chain/arweave/proto/codec.proto @@ -0,0 +1,521 @@ +syntax = "proto3"; + +package sf.near.codec.v1; + +option go_package = "github.com/streamingfast/sf-near/pb/sf/near/codec/v1;pbcodec"; + +message Block { + string author = 1; + BlockHeader header = 2; + repeated ChunkHeader chunk_headers = 3; + repeated IndexerShard shards = 4; + repeated StateChangeWithCause state_changes = 5; +} + +// HeaderOnlyBlock is a standard [Block] structure where all other fields are +// removed so that hydrating that object from a [Block] bytes payload will +// drastically reduced allocated memory required to hold the full block. +// +// This can be used to unpack a [Block] when only the [BlockHeader] information +// is required and greatly reduced required memory. +message HeaderOnlyBlock { + BlockHeader header = 2; +} + +message StateChangeWithCause { + StateChangeValue value = 1; + StateChangeCause cause = 2; +} + +message StateChangeCause { + oneof cause { + NotWritableToDisk not_writable_to_disk = 1; + InitialState initial_state = 2; + TransactionProcessing transaction_processing = 3; + ActionReceiptProcessingStarted action_receipt_processing_started = 4; + ActionReceiptGasReward action_receipt_gas_reward = 5; + ReceiptProcessing receipt_processing = 6; + PostponedReceipt postponed_receipt = 7; + UpdatedDelayedReceipts updated_delayed_receipts = 8; + ValidatorAccountsUpdate validator_accounts_update = 9; + Migration migration = 10; + } + + message NotWritableToDisk {} + message InitialState {} + message TransactionProcessing {CryptoHash tx_hash = 1;} + message ActionReceiptProcessingStarted {CryptoHash receipt_hash = 1;} + message ActionReceiptGasReward {CryptoHash tx_hash = 1;} + message ReceiptProcessing {CryptoHash tx_hash = 1;} + message PostponedReceipt {CryptoHash tx_hash = 1;} + message UpdatedDelayedReceipts {} + message ValidatorAccountsUpdate {} + message Migration {} +} + +message StateChangeValue { + oneof value { + AccountUpdate account_update = 1; + AccountDeletion account_deletion = 2; + AccessKeyUpdate access_key_update = 3; + AccessKeyDeletion access_key_deletion = 4; + DataUpdate data_update = 5; + DataDeletion data_deletion = 6; + ContractCodeUpdate contract_code_update = 7; + ContractCodeDeletion contract_deletion = 8; + } + + message AccountUpdate {string account_id = 1; Account account = 2;} + message AccountDeletion {string account_id = 1;} + message AccessKeyUpdate { + string account_id = 1; + PublicKey public_key = 2; + AccessKey access_key = 3; + } + message AccessKeyDeletion { + string account_id = 1; + PublicKey public_key = 2; + } + message DataUpdate { + string account_id = 1; + bytes key = 2; + bytes value = 3; + } + message DataDeletion { + string account_id = 1; + bytes key = 2; + } + message ContractCodeUpdate { + string account_id = 1; + bytes code = 2; + } + message ContractCodeDeletion { + string account_id = 1; + } +} + +message Account { + BigInt amount = 1; + BigInt locked = 2; + CryptoHash code_hash = 3; + uint64 storage_usage = 4; +} + +message BlockHeader { + uint64 height = 1; + uint64 prev_height = 2; + CryptoHash epoch_id = 3; + CryptoHash next_epoch_id = 4; + CryptoHash hash = 5; + CryptoHash prev_hash = 6; + CryptoHash prev_state_root = 7; + CryptoHash chunk_receipts_root = 8; + CryptoHash chunk_headers_root = 9; + CryptoHash chunk_tx_root = 10; + CryptoHash outcome_root = 11; + uint64 chunks_included = 12; + CryptoHash challenges_root = 13; + uint64 timestamp = 14; + uint64 timestamp_nanosec = 15; + CryptoHash random_value = 16; + repeated ValidatorStake validator_proposals = 17; + repeated bool chunk_mask = 18; + BigInt gas_price = 19; + uint64 block_ordinal = 20; + BigInt total_supply = 21; + repeated SlashedValidator challenges_result = 22; + uint64 last_final_block_height = 23; + CryptoHash last_final_block = 24; + uint64 last_ds_final_block_height = 25; + CryptoHash last_ds_final_block = 26; + CryptoHash next_bp_hash = 27; + CryptoHash block_merkle_root = 28; + bytes epoch_sync_data_hash = 29; + repeated Signature approvals = 30; + Signature signature = 31; + uint32 latest_protocol_version = 32; +} + +message BigInt { + bytes bytes = 1; +} +message CryptoHash { + bytes bytes = 1; +} + +enum CurveKind { + ED25519 = 0; + SECP256K1 = 1; +} + +message Signature { + CurveKind type = 1; + bytes bytes = 2; +} + +message PublicKey { + CurveKind type = 1; + bytes bytes = 2; +} + +message ValidatorStake { + string account_id = 1; + PublicKey public_key = 2; + BigInt stake = 3; +} + +message SlashedValidator { + string account_id = 1; + bool is_double_sign = 2; +} + +message ChunkHeader { + bytes chunk_hash = 1; + bytes prev_block_hash = 2; + bytes outcome_root = 3; + bytes prev_state_root = 4; + bytes encoded_merkle_root = 5; + uint64 encoded_length = 6; + uint64 height_created = 7; + uint64 height_included = 8; + uint64 shard_id = 9; + uint64 gas_used = 10; + uint64 gas_limit = 11; + BigInt validator_reward = 12; + BigInt balance_burnt = 13; + bytes outgoing_receipts_root = 14; + bytes tx_root = 15; + repeated ValidatorStake validator_proposals = 16; + Signature signature = 17; +} + +message IndexerShard { + uint64 shard_id = 1; + IndexerChunk chunk = 2; + repeated IndexerExecutionOutcomeWithReceipt receipt_execution_outcomes = 3; +} + +message IndexerExecutionOutcomeWithReceipt { + ExecutionOutcomeWithId execution_outcome = 1; + Receipt receipt = 2; +} + +message IndexerChunk { + string author = 1; + ChunkHeader header = 2; + repeated IndexerTransactionWithOutcome transactions = 3; + repeated Receipt receipts = 4; +} + +message IndexerTransactionWithOutcome { + SignedTransaction transaction = 1; + IndexerExecutionOutcomeWithOptionalReceipt outcome = 2; +} + +message SignedTransaction { + string signer_id = 1; + PublicKey public_key = 2; + uint64 nonce = 3; + string receiver_id = 4; + repeated Action actions = 5; + Signature signature = 6; + CryptoHash hash = 7; +} + +message IndexerExecutionOutcomeWithOptionalReceipt { + ExecutionOutcomeWithId execution_outcome = 1; + Receipt receipt = 2; +} + +message Receipt { + string predecessor_id = 1; + string receiver_id = 2; + CryptoHash receipt_id = 3; + + oneof receipt { + ReceiptAction action = 10; + ReceiptData data = 11; + } +} + +message ReceiptData { + CryptoHash data_id = 1; + bytes data = 2; +} + +message ReceiptAction { + string signer_id = 1; + PublicKey signer_public_key = 2; + BigInt gas_price = 3; + repeated DataReceiver output_data_receivers = 4; + repeated CryptoHash input_data_ids = 5; + repeated Action actions = 6; +} + +message DataReceiver { + CryptoHash data_id = 1; + string receiver_id = 2; +} + +message ExecutionOutcomeWithId { + MerklePath proof = 1; + CryptoHash block_hash = 2; + CryptoHash id = 3; + ExecutionOutcome outcome = 4; +} + +message ExecutionOutcome { + repeated string logs = 1; + repeated CryptoHash receipt_ids = 2; + uint64 gas_burnt = 3; + BigInt tokens_burnt = 4; + string executor_id = 5; + oneof status { + UnknownExecutionStatus unknown = 20; + FailureExecutionStatus failure = 21; + SuccessValueExecutionStatus success_value = 22; + SuccessReceiptIdExecutionStatus success_receipt_id = 23; + } + ExecutionMetadata metadata = 6; +} + +enum ExecutionMetadata { + ExecutionMetadataV1 = 0; +} + +message SuccessValueExecutionStatus { + bytes value = 1; +} + +message SuccessReceiptIdExecutionStatus { + CryptoHash id = 1; +} + +message UnknownExecutionStatus {} +message FailureExecutionStatus { + oneof failure { + ActionError action_error = 1; + InvalidTxError invalid_tx_error = 2; + } +} + +message ActionError { + uint64 index = 1; + oneof kind { + AccountAlreadyExistsErrorKind account_already_exist = 21; + AccountDoesNotExistErrorKind account_does_not_exist = 22; + CreateAccountOnlyByRegistrarErrorKind create_account_only_by_registrar = 23; + CreateAccountNotAllowedErrorKind create_account_not_allowed = 24; + ActorNoPermissionErrorKind actor_no_permission =25; + DeleteKeyDoesNotExistErrorKind delete_key_does_not_exist = 26; + AddKeyAlreadyExistsErrorKind add_key_already_exists = 27; + DeleteAccountStakingErrorKind delete_account_staking = 28; + LackBalanceForStateErrorKind lack_balance_for_state = 29; + TriesToUnstakeErrorKind tries_to_unstake = 30; + TriesToStakeErrorKind tries_to_stake = 31; + InsufficientStakeErrorKind insufficient_stake = 32; + FunctionCallErrorKind function_call = 33; + NewReceiptValidationErrorKind new_receipt_validation = 34; + OnlyImplicitAccountCreationAllowedErrorKind only_implicit_account_creation_allowed = 35; + DeleteAccountWithLargeStateErrorKind delete_account_with_large_state = 36; + } +} + +message AccountAlreadyExistsErrorKind { + string account_id = 1; +} + +message AccountDoesNotExistErrorKind { + string account_id = 1; +} + +/// A top-level account ID can only be created by registrar. +message CreateAccountOnlyByRegistrarErrorKind{ + string account_id = 1; + string registrar_account_id = 2; + string predecessor_id = 3; +} + +message CreateAccountNotAllowedErrorKind{ + string account_id = 1; + string predecessor_id = 2; +} + +message ActorNoPermissionErrorKind{ + string account_id = 1; + string actor_id = 2; +} + +message DeleteKeyDoesNotExistErrorKind{ + string account_id = 1; + PublicKey public_key = 2; +} + +message AddKeyAlreadyExistsErrorKind{ + string account_id = 1; + PublicKey public_key = 2; +} + +message DeleteAccountStakingErrorKind{ + string account_id = 1; +} + +message LackBalanceForStateErrorKind{ + string account_id = 1; + BigInt balance = 2; +} + +message TriesToUnstakeErrorKind{ + string account_id = 1; +} + +message TriesToStakeErrorKind{ + string account_id = 1; + BigInt stake = 2; + BigInt locked = 3; + BigInt balance = 4; +} + +message InsufficientStakeErrorKind{ + string account_id = 1; + BigInt stake = 2; + BigInt minimum_stake = 3; +} + +message FunctionCallErrorKind { + FunctionCallErrorSer error = 1; +} + +enum FunctionCallErrorSer { //todo: add more detail? + CompilationError = 0; + LinkError = 1; + MethodResolveError = 2; + WasmTrap = 3; + WasmUnknownError = 4; + HostError = 5; + _EVMError = 6; + ExecutionError = 7; +} + +message NewReceiptValidationErrorKind { + ReceiptValidationError error = 1; +} + +enum ReceiptValidationError { //todo: add more detail? + InvalidPredecessorId = 0; + InvalidReceiverAccountId = 1; + InvalidSignerAccountId = 2; + InvalidDataReceiverId = 3; + ReturnedValueLengthExceeded = 4; + NumberInputDataDependenciesExceeded = 5; + ActionsValidationError = 6; +} + +message OnlyImplicitAccountCreationAllowedErrorKind{ + string account_id = 1; +} + +message DeleteAccountWithLargeStateErrorKind{ + string account_id = 1; +} + +enum InvalidTxError { //todo: add more detail? + InvalidAccessKeyError = 0; + InvalidSignerId = 1; + SignerDoesNotExist = 2; + InvalidNonce = 3; + NonceTooLarge = 4; + InvalidReceiverId = 5; + InvalidSignature = 6; + NotEnoughBalance = 7; + LackBalanceForState = 8; + CostOverflow = 9; + InvalidChain = 10; + Expired = 11; + ActionsValidation = 12; + TransactionSizeExceeded = 13; +} + +message MerklePath { + repeated MerklePathItem path = 1; +} + +message MerklePathItem { + CryptoHash hash = 1; + Direction direction = 2; +} + +enum Direction { + left = 0; + right = 1; +} + +message Action { + oneof action { + CreateAccountAction create_account = 1; + DeployContractAction deploy_contract = 2; + FunctionCallAction function_call = 3; + TransferAction transfer = 4; + StakeAction stake = 5; + AddKeyAction add_key = 6; + DeleteKeyAction delete_key = 7; + DeleteAccountAction delete_account = 8; + } +} + +message CreateAccountAction { +} + +message DeployContractAction { + bytes code = 1; +} + +message FunctionCallAction { + string method_name = 1; + bytes args = 2; + uint64 gas = 3; + BigInt deposit = 4; +} + +message TransferAction { + BigInt deposit = 1; +} + +message StakeAction { + BigInt stake = 1; + PublicKey public_key = 2; +} + +message AddKeyAction { + PublicKey public_key = 1; + AccessKey access_key = 2; +} + +message DeleteKeyAction { + PublicKey public_key = 1; +} + +message DeleteAccountAction { + string beneficiary_id = 1; +} + +message AccessKey { + uint64 nonce = 1; + AccessKeyPermission permission = 2; +} + +message AccessKeyPermission { + oneof permission { + FunctionCallPermission function_call = 1; + FullAccessPermission full_access = 2; + } +} + +message FunctionCallPermission { + BigInt allowance = 1; + string receiver_id = 2; + repeated string method_names = 3; +} + +message FullAccessPermission { +} diff --git a/chain/arweave/src/adapter.rs b/chain/arweave/src/adapter.rs new file mode 100644 index 00000000000..33c47e9bc51 --- /dev/null +++ b/chain/arweave/src/adapter.rs @@ -0,0 +1,204 @@ +use std::collections::HashSet; + +use crate::capabilities::NodeCapabilities; +use crate::{data_source::DataSource, Chain}; +use graph::blockchain as bc; +use graph::firehose::BasicReceiptFilter; +use graph::prelude::*; +use prost::Message; +use prost_types::Any; + +const BASIC_RECEIPT_FILTER_TYPE_URL: &str = + "type.googleapis.com/sf.near.transform.v1.BasicReceiptFilter"; + +#[derive(Clone, Debug, Default)] +pub struct TriggerFilter { + pub(crate) block_filter: NearBlockFilter, + pub(crate) receipt_filter: NearReceiptFilter, +} + +impl bc::TriggerFilter for TriggerFilter { + fn extend<'a>(&mut self, data_sources: impl Iterator + Clone) { + let TriggerFilter { + block_filter, + receipt_filter, + } = self; + + block_filter.extend(NearBlockFilter::from_data_sources(data_sources.clone())); + receipt_filter.extend(NearReceiptFilter::from_data_sources(data_sources)); + } + + fn node_capabilities(&self) -> NodeCapabilities { + NodeCapabilities {} + } + + fn extend_with_template( + &mut self, + _data_source: impl Iterator::DataSourceTemplate>, + ) { + } + + fn to_firehose_filter(self) -> Vec { + let TriggerFilter { + block_filter: block, + receipt_filter: receipt, + } = self; + + if block.trigger_every_block { + return vec![]; + } + + if receipt.is_empty() { + return vec![]; + } + + let filter = BasicReceiptFilter { + accounts: receipt.accounts.into_iter().collect(), + }; + + vec![Any { + type_url: BASIC_RECEIPT_FILTER_TYPE_URL.into(), + value: filter.encode_to_vec(), + }] + } +} + +pub(crate) type Account = String; + +/// NearReceiptFilter requires the account to be set, it will match every receipt where `source.account` is the recipient. +/// see docs: https://thegraph.com/docs/en/supported-networks/near/ +#[derive(Clone, Debug, Default)] +pub(crate) struct NearReceiptFilter { + pub accounts: HashSet, +} + +impl NearReceiptFilter { + pub fn matches(&self, account: &String) -> bool { + self.accounts.contains(account) + } + + pub fn is_empty(&self) -> bool { + let NearReceiptFilter { accounts } = self; + + accounts.is_empty() + } + + pub fn from_data_sources<'a>(iter: impl IntoIterator) -> Self { + let accounts: Vec = iter + .into_iter() + .filter(|data_source| { + data_source.source.account.is_some() + && !data_source.mapping.receipt_handlers.is_empty() + }) + .map(|ds| ds.source.account.as_ref().unwrap().clone()) + .collect(); + + Self { + accounts: HashSet::from_iter(accounts), + } + } + + pub fn extend(&mut self, other: NearReceiptFilter) { + self.accounts.extend(other.accounts); + } +} + +/// NearBlockFilter will match every block regardless of source being set. +/// see docs: https://thegraph.com/docs/en/supported-networks/near/ +#[derive(Clone, Debug, Default)] +pub(crate) struct NearBlockFilter { + pub trigger_every_block: bool, +} + +impl NearBlockFilter { + pub fn from_data_sources<'a>(iter: impl IntoIterator) -> Self { + Self { + trigger_every_block: iter + .into_iter() + .any(|data_source| !data_source.mapping.block_handlers.is_empty()), + } + } + + pub fn extend(&mut self, other: NearBlockFilter) { + self.trigger_every_block = self.trigger_every_block || other.trigger_every_block; + } +} + +#[cfg(test)] +mod test { + use std::collections::HashSet; + + use super::NearBlockFilter; + use crate::adapter::{TriggerFilter, BASIC_RECEIPT_FILTER_TYPE_URL}; + use graph::{blockchain::TriggerFilter as _, firehose::BasicReceiptFilter}; + use prost::Message; + use prost_types::Any; + + #[test] + fn near_trigger_empty_filter() { + let filter = TriggerFilter { + block_filter: NearBlockFilter { + trigger_every_block: false, + }, + receipt_filter: super::NearReceiptFilter { + accounts: HashSet::new(), + }, + }; + assert_eq!(filter.to_firehose_filter(), vec![]); + } + + #[test] + fn near_trigger_filter_match_all_block() { + let filter = TriggerFilter { + block_filter: NearBlockFilter { + trigger_every_block: true, + }, + receipt_filter: super::NearReceiptFilter { + accounts: HashSet::from_iter(vec!["acc1".into(), "acc2".into(), "acc3".into()]), + }, + }; + + let filter = filter.to_firehose_filter(); + assert_eq!(filter.len(), 0); + } + + #[test] + fn near_trigger_filter() { + let filter = TriggerFilter { + block_filter: NearBlockFilter { + trigger_every_block: false, + }, + receipt_filter: super::NearReceiptFilter { + accounts: HashSet::from_iter(vec!["acc1".into(), "acc2".into(), "acc3".into()]), + }, + }; + + let filter = filter.to_firehose_filter(); + assert_eq!(filter.len(), 1); + + let firehose_filter = decode_filter(filter); + + assert_eq!( + firehose_filter.accounts, + vec![ + String::from("acc1"), + String::from("acc2"), + String::from("acc3") + ], + ); + } + + fn decode_filter(firehose_filter: Vec) -> BasicReceiptFilter { + let firehose_filter = firehose_filter[0].clone(); + assert_eq!( + firehose_filter.type_url, + String::from(BASIC_RECEIPT_FILTER_TYPE_URL), + ); + let mut bytes = &firehose_filter.value[..]; + let mut firehose_filter = + BasicReceiptFilter::decode(&mut bytes).expect("unable to parse basic receipt filter"); + firehose_filter.accounts.sort(); + + firehose_filter + } +} diff --git a/chain/arweave/src/capabilities.rs b/chain/arweave/src/capabilities.rs new file mode 100644 index 00000000000..0d84c9c555d --- /dev/null +++ b/chain/arweave/src/capabilities.rs @@ -0,0 +1,37 @@ +use graph::{anyhow::Error, impl_slog_value}; +use std::cmp::{Ordering, PartialOrd}; +use std::fmt; +use std::str::FromStr; + +use crate::data_source::DataSource; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct NodeCapabilities {} + +impl PartialOrd for NodeCapabilities { + fn partial_cmp(&self, _other: &Self) -> Option { + None + } +} + +impl FromStr for NodeCapabilities { + type Err = Error; + + fn from_str(_s: &str) -> Result { + Ok(NodeCapabilities {}) + } +} + +impl fmt::Display for NodeCapabilities { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("near") + } +} + +impl_slog_value!(NodeCapabilities, "{}"); + +impl graph::blockchain::NodeCapabilities for NodeCapabilities { + fn from_data_sources(_data_sources: &[DataSource]) -> Self { + NodeCapabilities {} + } +} diff --git a/chain/arweave/src/chain.rs b/chain/arweave/src/chain.rs new file mode 100644 index 00000000000..a472a78fe7c --- /dev/null +++ b/chain/arweave/src/chain.rs @@ -0,0 +1,508 @@ +use graph::blockchain::BlockchainKind; +use graph::cheap_clone::CheapClone; +use graph::data::subgraph::UnifiedMappingApiVersion; +use graph::firehose::{FirehoseEndpoint, FirehoseEndpoints}; +use graph::prelude::{MetricsRegistry, TryFutureExt}; +use graph::{ + anyhow, + blockchain::{ + block_stream::{ + BlockStreamEvent, BlockWithTriggers, FirehoseError, + FirehoseMapper as FirehoseMapperTrait, TriggersAdapter as TriggersAdapterTrait, + }, + firehose_block_stream::FirehoseBlockStream, + BlockHash, BlockPtr, Blockchain, IngestorError, + }, + components::store::DeploymentLocator, + firehose::{self as firehose, ForkStep}, + prelude::{async_trait, o, BlockNumber, ChainStore, Error, Logger, LoggerFactory}, +}; +use prost::Message; +use std::sync::Arc; + +use crate::adapter::TriggerFilter; +use crate::capabilities::NodeCapabilities; +use crate::data_source::{DataSourceTemplate, UnresolvedDataSourceTemplate}; +use crate::runtime::RuntimeAdapter; +use crate::trigger::{self, NearTrigger}; +use crate::{ + codec, + data_source::{DataSource, UnresolvedDataSource}, +}; +use graph::blockchain::block_stream::BlockStream; + +pub struct Chain { + logger_factory: LoggerFactory, + name: String, + firehose_endpoints: Arc, + chain_store: Arc, + metrics_registry: Arc, +} + +impl std::fmt::Debug for Chain { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "chain: near") + } +} + +impl Chain { + pub fn new( + logger_factory: LoggerFactory, + name: String, + chain_store: Arc, + firehose_endpoints: FirehoseEndpoints, + metrics_registry: Arc, + ) -> Self { + Chain { + logger_factory, + name, + firehose_endpoints: Arc::new(firehose_endpoints), + chain_store, + metrics_registry, + } + } +} + +#[async_trait] +impl Blockchain for Chain { + const KIND: BlockchainKind = BlockchainKind::Near; + + type Block = codec::Block; + + type DataSource = DataSource; + + type UnresolvedDataSource = UnresolvedDataSource; + + type DataSourceTemplate = DataSourceTemplate; + + type UnresolvedDataSourceTemplate = UnresolvedDataSourceTemplate; + + type TriggersAdapter = TriggersAdapter; + + type TriggerData = crate::trigger::NearTrigger; + + type MappingTrigger = crate::trigger::NearTrigger; + + type TriggerFilter = crate::adapter::TriggerFilter; + + type NodeCapabilities = crate::capabilities::NodeCapabilities; + + type RuntimeAdapter = RuntimeAdapter; + + fn triggers_adapter( + &self, + _loc: &DeploymentLocator, + _capabilities: &Self::NodeCapabilities, + _unified_api_version: UnifiedMappingApiVersion, + ) -> Result, Error> { + let adapter = TriggersAdapter {}; + Ok(Arc::new(adapter)) + } + + async fn new_firehose_block_stream( + &self, + deployment: DeploymentLocator, + block_cursor: Option, + start_blocks: Vec, + subgraph_current_block: Option, + filter: Arc, + unified_api_version: UnifiedMappingApiVersion, + ) -> Result>, Error> { + let adapter = self + .triggers_adapter(&deployment, &NodeCapabilities {}, unified_api_version) + .expect(&format!("no adapter for network {}", self.name,)); + + let firehose_endpoint = match self.firehose_endpoints.random() { + Some(e) => e.clone(), + None => return Err(anyhow::format_err!("no firehose endpoint available")), + }; + + let logger = self + .logger_factory + .subgraph_logger(&deployment) + .new(o!("component" => "FirehoseBlockStream")); + + let firehose_mapper = Arc::new(FirehoseMapper { + endpoint: firehose_endpoint.cheap_clone(), + }); + + Ok(Box::new(FirehoseBlockStream::new( + deployment.hash, + firehose_endpoint, + subgraph_current_block, + block_cursor, + firehose_mapper, + adapter, + filter, + start_blocks, + logger, + self.metrics_registry.clone(), + ))) + } + + async fn new_polling_block_stream( + &self, + _deployment: DeploymentLocator, + _start_blocks: Vec, + _subgraph_current_block: Option, + _filter: Arc, + _unified_api_version: UnifiedMappingApiVersion, + ) -> Result>, Error> { + panic!("NEAR does not support polling block stream") + } + + fn chain_store(&self) -> Arc { + self.chain_store.clone() + } + + async fn block_pointer_from_number( + &self, + logger: &Logger, + number: BlockNumber, + ) -> Result { + let firehose_endpoint = match self.firehose_endpoints.random() { + Some(e) => e.clone(), + None => return Err(anyhow::format_err!("no firehose endpoint available").into()), + }; + + firehose_endpoint + .block_ptr_for_number::(logger, number) + .map_err(Into::into) + .await + } + + fn runtime_adapter(&self) -> Arc { + Arc::new(RuntimeAdapter {}) + } + + fn is_firehose_supported(&self) -> bool { + true + } +} + +pub struct TriggersAdapter {} + +#[async_trait] +impl TriggersAdapterTrait for TriggersAdapter { + async fn scan_triggers( + &self, + _from: BlockNumber, + _to: BlockNumber, + _filter: &TriggerFilter, + ) -> Result>, Error> { + panic!("Should never be called since not used by FirehoseBlockStream") + } + + async fn triggers_in_block( + &self, + _logger: &Logger, + block: codec::Block, + filter: &TriggerFilter, + ) -> Result, Error> { + // TODO: Find the best place to introduce an `Arc` and avoid this clone. + let shared_block = Arc::new(block.clone()); + + let TriggerFilter { + block_filter, + receipt_filter, + } = filter; + + // Filter non-successful or non-action receipts. + let receipts = block.shards.iter().flat_map(|shard| { + shard + .receipt_execution_outcomes + .iter() + .filter_map(|outcome| { + if !outcome + .execution_outcome + .as_ref()? + .outcome + .as_ref()? + .status + .as_ref()? + .is_success() + { + return None; + } + if !matches!( + outcome.receipt.as_ref()?.receipt, + Some(codec::receipt::Receipt::Action(_)) + ) { + return None; + } + + let receipt = outcome.receipt.as_ref()?.clone(); + if !receipt_filter.matches(&receipt.receiver_id) { + return None; + } + + Some(trigger::ReceiptWithOutcome { + outcome: outcome.execution_outcome.as_ref()?.clone(), + receipt, + block: shared_block.cheap_clone(), + }) + }) + }); + + let mut trigger_data: Vec<_> = receipts + .map(|r| NearTrigger::Receipt(Arc::new(r))) + .collect(); + + if block_filter.trigger_every_block { + trigger_data.push(NearTrigger::Block(shared_block.cheap_clone())); + } + + Ok(BlockWithTriggers::new(block, trigger_data)) + } + + async fn is_on_main_chain(&self, _ptr: BlockPtr) -> Result { + panic!("Should never be called since not used by FirehoseBlockStream") + } + + async fn ancestor_block( + &self, + _ptr: BlockPtr, + _offset: BlockNumber, + ) -> Result, Error> { + panic!("Should never be called since FirehoseBlockStream cannot resolve it") + } + + /// Panics if `block` is genesis. + /// But that's ok since this is only called when reverting `block`. + async fn parent_ptr(&self, block: &BlockPtr) -> Result, Error> { + // FIXME (NEAR): Might not be necessary for NEAR support for now + Ok(Some(BlockPtr { + hash: BlockHash::from(vec![0xff; 32]), + number: block.number.saturating_sub(1), + })) + } +} + +pub struct FirehoseMapper { + endpoint: Arc, +} + +#[async_trait] +impl FirehoseMapperTrait for FirehoseMapper { + async fn to_block_stream_event( + &self, + logger: &Logger, + response: &firehose::Response, + adapter: &TriggersAdapter, + filter: &TriggerFilter, + ) -> Result, FirehoseError> { + let step = ForkStep::from_i32(response.step).unwrap_or_else(|| { + panic!( + "unknown step i32 value {}, maybe you forgot update & re-regenerate the protobuf definitions?", + response.step + ) + }); + + let any_block = response + .block + .as_ref() + .expect("block payload information should always be present"); + + // Right now, this is done in all cases but in reality, with how the BlockStreamEvent::Revert + // is defined right now, only block hash and block number is necessary. However, this information + // is not part of the actual bstream::BlockResponseV2 payload. As such, we need to decode the full + // block which is useless. + // + // Check about adding basic information about the block in the bstream::BlockResponseV2 or maybe + // define a slimmed down stuct that would decode only a few fields and ignore all the rest. + let block = codec::Block::decode(any_block.value.as_ref())?; + + use ForkStep::*; + match step { + StepNew => Ok(BlockStreamEvent::ProcessBlock( + adapter.triggers_in_block(logger, block, filter).await?, + Some(response.cursor.clone()), + )), + + StepUndo => { + let parent_ptr = block + .header() + .parent_ptr() + .expect("Genesis block should never be reverted"); + + Ok(BlockStreamEvent::Revert( + parent_ptr, + Some(response.cursor.clone()), + )) + } + + StepIrreversible => { + panic!("irreversible step is not handled and should not be requested in the Firehose request") + } + + StepUnknown => { + panic!("unknown step should not happen in the Firehose response") + } + } + } + + async fn block_ptr_for_number( + &self, + logger: &Logger, + number: BlockNumber, + ) -> Result { + self.endpoint + .block_ptr_for_number::(logger, number) + .await + } + + async fn final_block_ptr_for( + &self, + logger: &Logger, + block: &codec::Block, + ) -> Result { + let final_block_number = block.header().last_final_block_height as BlockNumber; + + self.endpoint + .block_ptr_for_number::(logger, final_block_number) + .await + } +} + +#[cfg(test)] +mod test { + use std::{collections::HashSet, vec}; + + use graph::{ + blockchain::{block_stream::BlockWithTriggers, TriggersAdapter as _}, + prelude::tokio, + slog::{self, o, Logger}, + }; + + use crate::{ + adapter::{NearReceiptFilter, TriggerFilter}, + codec::{ + self, execution_outcome, + receipt::{self}, + BlockHeader, DataReceiver, ExecutionOutcome, ExecutionOutcomeWithId, + IndexerExecutionOutcomeWithReceipt, IndexerShard, ReceiptAction, + SuccessValueExecutionStatus, + }, + Chain, + }; + + use super::TriggersAdapter; + + #[tokio::test] + async fn test_trigger_filter_empty() { + let account1: String = "account1".into(); + + let adapter = TriggersAdapter {}; + + let logger = Logger::root(slog::Discard, o!()); + let block1 = new_success_block(1, &account1); + + let filter = TriggerFilter::default(); + + let block_with_triggers: BlockWithTriggers = adapter + .triggers_in_block(&logger, block1, &filter) + .await + .expect("failed to execute triggers_in_block"); + assert_eq!(block_with_triggers.trigger_count(), 0); + } + + #[tokio::test] + async fn test_trigger_filter_every_block() { + let account1: String = "account1".into(); + + let adapter = TriggersAdapter {}; + + let logger = Logger::root(slog::Discard, o!()); + let block1 = new_success_block(1, &account1); + + let filter = TriggerFilter { + block_filter: crate::adapter::NearBlockFilter { + trigger_every_block: true, + }, + ..Default::default() + }; + + let block_with_triggers: BlockWithTriggers = adapter + .triggers_in_block(&logger, block1, &filter) + .await + .expect("failed to execute triggers_in_block"); + assert_eq!(block_with_triggers.trigger_count(), 1); + + let height: Vec = heights_from_triggers(&block_with_triggers); + assert_eq!(height, vec![1]); + } + + #[tokio::test] + async fn test_trigger_filter_every_receipt() { + let account1: String = "account1".into(); + + let adapter = TriggersAdapter {}; + + let logger = Logger::root(slog::Discard, o!()); + let block1 = new_success_block(1, &account1); + + let filter = TriggerFilter { + receipt_filter: NearReceiptFilter { + accounts: HashSet::from_iter(vec![account1]), + }, + ..Default::default() + }; + + let block_with_triggers: BlockWithTriggers = adapter + .triggers_in_block(&logger, block1, &filter) + .await + .expect("failed to execute triggers_in_block"); + assert_eq!(block_with_triggers.trigger_count(), 1); + + let height: Vec = heights_from_triggers(&block_with_triggers); + assert_eq!(height.len(), 0); + } + + fn heights_from_triggers(block: &BlockWithTriggers) -> Vec { + block + .trigger_data + .clone() + .into_iter() + .filter_map(|x| match x { + crate::trigger::NearTrigger::Block(b) => b.header.clone().map(|x| x.height), + _ => None, + }) + .collect() + } + + fn new_success_block(height: u64, receiver_id: &String) -> codec::Block { + codec::Block { + header: Some(BlockHeader { + height, + ..Default::default() + }), + shards: vec![IndexerShard { + receipt_execution_outcomes: vec![IndexerExecutionOutcomeWithReceipt { + receipt: Some(crate::codec::Receipt { + receipt: Some(receipt::Receipt::Action(ReceiptAction { + output_data_receivers: vec![DataReceiver { + receiver_id: receiver_id.clone(), + ..Default::default() + }], + ..Default::default() + })), + receiver_id: receiver_id.clone(), + ..Default::default() + }), + execution_outcome: Some(ExecutionOutcomeWithId { + outcome: Some(ExecutionOutcome { + status: Some(execution_outcome::Status::SuccessValue( + SuccessValueExecutionStatus::default(), + )), + + ..Default::default() + }), + ..Default::default() + }), + }], + ..Default::default() + }], + ..Default::default() + } + } +} diff --git a/chain/arweave/src/codec.rs b/chain/arweave/src/codec.rs new file mode 100644 index 00000000000..cfc26b20b0c --- /dev/null +++ b/chain/arweave/src/codec.rs @@ -0,0 +1,109 @@ +#[path = "protobuf/sf.near.codec.v1.rs"] +mod pbcodec; + +use graph::{ + blockchain::Block as BlockchainBlock, + blockchain::BlockPtr, + prelude::{hex, web3::types::H256, BlockNumber}, +}; +use std::convert::TryFrom; +use std::fmt::LowerHex; + +pub use pbcodec::*; + +impl From<&CryptoHash> for H256 { + fn from(input: &CryptoHash) -> Self { + H256::from_slice(&input.bytes) + } +} + +impl LowerHex for &CryptoHash { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&hex::encode(&self.bytes)) + } +} + +impl BlockHeader { + pub fn parent_ptr(&self) -> Option { + match (self.prev_hash.as_ref(), self.prev_height) { + (Some(hash), number) => Some(BlockPtr::from((H256::from(hash), number))), + _ => None, + } + } +} + +impl<'a> From<&'a BlockHeader> for BlockPtr { + fn from(b: &'a BlockHeader) -> BlockPtr { + BlockPtr::from((H256::from(b.hash.as_ref().unwrap()), b.height)) + } +} + +impl Block { + pub fn header(&self) -> &BlockHeader { + self.header.as_ref().unwrap() + } + + pub fn ptr(&self) -> BlockPtr { + BlockPtr::from(self.header()) + } + + pub fn parent_ptr(&self) -> Option { + self.header().parent_ptr() + } +} + +impl<'a> From<&'a Block> for BlockPtr { + fn from(b: &'a Block) -> BlockPtr { + BlockPtr::from(b.header()) + } +} + +impl BlockchainBlock for Block { + fn number(&self) -> i32 { + BlockNumber::try_from(self.header().height).unwrap() + } + + fn ptr(&self) -> BlockPtr { + self.into() + } + + fn parent_ptr(&self) -> Option { + self.parent_ptr() + } +} + +impl HeaderOnlyBlock { + pub fn header(&self) -> &BlockHeader { + self.header.as_ref().unwrap() + } +} + +impl<'a> From<&'a HeaderOnlyBlock> for BlockPtr { + fn from(b: &'a HeaderOnlyBlock) -> BlockPtr { + BlockPtr::from(b.header()) + } +} + +impl BlockchainBlock for HeaderOnlyBlock { + fn number(&self) -> i32 { + BlockNumber::try_from(self.header().height).unwrap() + } + + fn ptr(&self) -> BlockPtr { + self.into() + } + + fn parent_ptr(&self) -> Option { + self.header().parent_ptr() + } +} + +impl execution_outcome::Status { + pub fn is_success(&self) -> bool { + use execution_outcome::Status::*; + match self { + Unknown(_) | Failure(_) => false, + SuccessValue(_) | SuccessReceiptId(_) => true, + } + } +} diff --git a/chain/arweave/src/data_source.rs b/chain/arweave/src/data_source.rs new file mode 100644 index 00000000000..c0ae002c38c --- /dev/null +++ b/chain/arweave/src/data_source.rs @@ -0,0 +1,403 @@ +use graph::blockchain::{Block, TriggerWithHandler}; +use graph::components::store::StoredDynamicDataSource; +use graph::data::subgraph::DataSourceContext; +use graph::prelude::SubgraphManifestValidationError; +use graph::{ + anyhow::{anyhow, Error}, + blockchain::{self, Blockchain}, + prelude::{ + async_trait, info, BlockNumber, CheapClone, DataSourceTemplateInfo, Deserialize, Link, + LinkResolver, Logger, + }, + semver, +}; +use std::collections::BTreeMap; +use std::{convert::TryFrom, sync::Arc}; + +use crate::chain::Chain; +use crate::trigger::NearTrigger; + +pub const NEAR_KIND: &str = "near"; + +/// Runtime representation of a data source. +#[derive(Clone, Debug)] +pub struct DataSource { + pub kind: String, + pub network: Option, + pub name: String, + pub(crate) source: Source, + pub mapping: Mapping, + pub context: Arc>, + pub creation_block: Option, +} + +impl blockchain::DataSource for DataSource { + fn address(&self) -> Option<&[u8]> { + self.source.account.as_ref().map(String::as_bytes) + } + + fn start_block(&self) -> BlockNumber { + self.source.start_block + } + + fn match_and_decode( + &self, + trigger: &::TriggerData, + block: &Arc<::Block>, + _logger: &Logger, + ) -> Result>, Error> { + if self.source.start_block > block.number() { + return Ok(None); + } + + let handler = match trigger { + // A block trigger matches if a block handler is present. + NearTrigger::Block(_) => match self.handler_for_block() { + Some(handler) => &handler.handler, + None => return Ok(None), + }, + + // A receipt trigger matches if the receiver matches `source.account` and a receipt + // handler is present. + NearTrigger::Receipt(receipt) => { + if Some(&receipt.receipt.receiver_id) != self.source.account.as_ref() { + return Ok(None); + } + + match self.handler_for_receipt() { + Some(handler) => &handler.handler, + None => return Ok(None), + } + } + }; + + Ok(Some(TriggerWithHandler::new( + trigger.cheap_clone(), + handler.to_owned(), + ))) + } + + fn name(&self) -> &str { + &self.name + } + + fn kind(&self) -> &str { + &self.kind + } + + fn network(&self) -> Option<&str> { + self.network.as_ref().map(|s| s.as_str()) + } + + fn context(&self) -> Arc> { + self.context.cheap_clone() + } + + fn creation_block(&self) -> Option { + self.creation_block + } + + fn is_duplicate_of(&self, other: &Self) -> bool { + let DataSource { + kind, + network, + name, + source, + mapping, + context, + + // The creation block is ignored for detection duplicate data sources. + // Contract ABI equality is implicit in `source` and `mapping.abis` equality. + creation_block: _, + } = self; + + // mapping_request_sender, host_metrics, and (most of) host_exports are operational structs + // used at runtime but not needed to define uniqueness; each runtime host should be for a + // unique data source. + kind == &other.kind + && network == &other.network + && name == &other.name + && source == &other.source + && mapping.block_handlers == other.mapping.block_handlers + && context == &other.context + } + + fn as_stored_dynamic_data_source(&self) -> StoredDynamicDataSource { + // FIXME (NEAR): Implement me! + todo!() + } + + fn from_stored_dynamic_data_source( + _templates: &BTreeMap<&str, &DataSourceTemplate>, + _stored: StoredDynamicDataSource, + ) -> Result { + // FIXME (NEAR): Implement me correctly + todo!() + } + + fn validate(&self) -> Vec { + let mut errors = Vec::new(); + + if self.kind != NEAR_KIND { + errors.push(anyhow!( + "data source has invalid `kind`, expected {} but found {}", + NEAR_KIND, + self.kind + )) + } + + // Validate that there is a `source` address if there are receipt handlers + let no_source_address = self.address().is_none(); + let has_receipt_handlers = !self.mapping.receipt_handlers.is_empty(); + if no_source_address && has_receipt_handlers { + errors.push(SubgraphManifestValidationError::SourceAddressRequired.into()); + }; + + // Validate that there are no more than one of both block handlers and receipt handlers + if self.mapping.block_handlers.len() > 1 { + errors.push(anyhow!("data source has duplicated block handlers")); + } + if self.mapping.receipt_handlers.len() > 1 { + errors.push(anyhow!("data source has duplicated receipt handlers")); + } + + errors + } + + fn api_version(&self) -> semver::Version { + self.mapping.api_version.clone() + } + + fn runtime(&self) -> &[u8] { + self.mapping.runtime.as_ref() + } +} + +impl DataSource { + fn from_manifest( + kind: String, + network: Option, + name: String, + source: Source, + mapping: Mapping, + context: Option, + ) -> Result { + // Data sources in the manifest are created "before genesis" so they have no creation block. + let creation_block = None; + + Ok(DataSource { + kind, + network, + name, + source, + mapping, + context: Arc::new(context), + creation_block, + }) + } + + fn handler_for_block(&self) -> Option<&MappingBlockHandler> { + self.mapping.block_handlers.first() + } + + fn handler_for_receipt(&self) -> Option<&ReceiptHandler> { + self.mapping.receipt_handlers.first() + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize)] +pub struct UnresolvedDataSource { + pub kind: String, + pub network: Option, + pub name: String, + pub(crate) source: Source, + pub mapping: UnresolvedMapping, + pub context: Option, +} + +#[async_trait] +impl blockchain::UnresolvedDataSource for UnresolvedDataSource { + async fn resolve( + self, + resolver: &Arc, + logger: &Logger, + ) -> Result { + let UnresolvedDataSource { + kind, + network, + name, + source, + mapping, + context, + } = self; + + info!(logger, "Resolve data source"; "name" => &name, "source_account" => format_args!("{:?}", source.account), "source_start_block" => source.start_block); + + let mapping = mapping.resolve(resolver, logger).await?; + + DataSource::from_manifest(kind, network, name, source, mapping, context) + } +} + +impl TryFrom> for DataSource { + type Error = Error; + + fn try_from(_info: DataSourceTemplateInfo) -> Result { + Err(anyhow!("Near subgraphs do not support templates")) + + // How this might be implemented if/when Near gets support for templates: + // let DataSourceTemplateInfo { + // template, + // params, + // context, + // creation_block, + // } = info; + + // let account = params + // .get(0) + // .with_context(|| { + // format!( + // "Failed to create data source from template `{}`: account parameter is missing", + // template.name + // ) + // })? + // .clone(); + + // Ok(DataSource { + // kind: template.kind, + // network: template.network, + // name: template.name, + // source: Source { + // account, + // start_block: 0, + // }, + // mapping: template.mapping, + // context: Arc::new(context), + // creation_block: Some(creation_block), + // }) + } +} + +#[derive(Clone, Debug, Default, Hash, Eq, PartialEq, Deserialize)] +pub struct BaseDataSourceTemplate { + pub kind: String, + pub network: Option, + pub name: String, + pub mapping: M, +} + +pub type UnresolvedDataSourceTemplate = BaseDataSourceTemplate; +pub type DataSourceTemplate = BaseDataSourceTemplate; + +#[async_trait] +impl blockchain::UnresolvedDataSourceTemplate for UnresolvedDataSourceTemplate { + async fn resolve( + self, + resolver: &Arc, + logger: &Logger, + ) -> Result { + let UnresolvedDataSourceTemplate { + kind, + network, + name, + mapping, + } = self; + + info!(logger, "Resolve data source template"; "name" => &name); + + Ok(DataSourceTemplate { + kind, + network, + name, + mapping: mapping.resolve(resolver, logger).await?, + }) + } +} + +impl blockchain::DataSourceTemplate for DataSourceTemplate { + fn name(&self) -> &str { + &self.name + } + + fn api_version(&self) -> semver::Version { + self.mapping.api_version.clone() + } + + fn runtime(&self) -> &[u8] { + self.mapping.runtime.as_ref() + } +} + +#[derive(Clone, Debug, Default, Hash, Eq, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UnresolvedMapping { + pub api_version: String, + pub language: String, + pub entities: Vec, + #[serde(default)] + pub block_handlers: Vec, + #[serde(default)] + pub receipt_handlers: Vec, + pub file: Link, +} + +impl UnresolvedMapping { + pub async fn resolve( + self, + resolver: &Arc, + logger: &Logger, + ) -> Result { + let UnresolvedMapping { + api_version, + language, + entities, + block_handlers, + receipt_handlers, + file: link, + } = self; + + let api_version = semver::Version::parse(&api_version)?; + + info!(logger, "Resolve mapping"; "link" => &link.link); + let module_bytes = resolver.cat(logger, &link).await?; + + Ok(Mapping { + api_version, + language, + entities, + block_handlers, + receipt_handlers, + runtime: Arc::new(module_bytes), + link, + }) + } +} + +#[derive(Clone, Debug)] +pub struct Mapping { + pub api_version: semver::Version, + pub language: String, + pub entities: Vec, + pub block_handlers: Vec, + pub receipt_handlers: Vec, + pub runtime: Arc>, + pub link: Link, +} + +#[derive(Clone, Debug, Hash, Eq, PartialEq, Deserialize)] +pub struct MappingBlockHandler { + pub handler: String, +} + +#[derive(Clone, Debug, Hash, Eq, PartialEq, Deserialize)] +pub struct ReceiptHandler { + handler: String, +} + +#[derive(Clone, Debug, Hash, Eq, PartialEq, Deserialize)] +pub(crate) struct Source { + // A data source that does not have an account can only have block handlers. + pub(crate) account: Option, + #[serde(rename = "startBlock", default)] + pub(crate) start_block: BlockNumber, +} diff --git a/chain/arweave/src/lib.rs b/chain/arweave/src/lib.rs new file mode 100644 index 00000000000..9b1ddab5ce2 --- /dev/null +++ b/chain/arweave/src/lib.rs @@ -0,0 +1,11 @@ +mod adapter; +mod capabilities; +mod chain; +mod codec; +mod data_source; +mod runtime; +mod trigger; + +pub use crate::chain::Chain; +pub use codec::Block; +pub use codec::HeaderOnlyBlock; diff --git a/chain/arweave/src/protobuf/sf.near.codec.v1.rs b/chain/arweave/src/protobuf/sf.near.codec.v1.rs new file mode 100644 index 00000000000..e587f72e8eb --- /dev/null +++ b/chain/arweave/src/protobuf/sf.near.codec.v1.rs @@ -0,0 +1,848 @@ +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Block { + #[prost(string, tag = "1")] + pub author: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub header: ::core::option::Option, + #[prost(message, repeated, tag = "3")] + pub chunk_headers: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "4")] + pub shards: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "5")] + pub state_changes: ::prost::alloc::vec::Vec, +} +/// HeaderOnlyBlock is a standard [Block] structure where all other fields are +/// removed so that hydrating that object from a [Block] bytes payload will +/// drastically reduced allocated memory required to hold the full block. +/// +/// This can be used to unpack a [Block] when only the [BlockHeader] information +/// is required and greatly reduced required memory. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HeaderOnlyBlock { + #[prost(message, optional, tag = "2")] + pub header: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StateChangeWithCause { + #[prost(message, optional, tag = "1")] + pub value: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub cause: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StateChangeCause { + #[prost( + oneof = "state_change_cause::Cause", + tags = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10" + )] + pub cause: ::core::option::Option, +} +/// Nested message and enum types in `StateChangeCause`. +pub mod state_change_cause { + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct NotWritableToDisk {} + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct InitialState {} + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct TransactionProcessing { + #[prost(message, optional, tag = "1")] + pub tx_hash: ::core::option::Option, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ActionReceiptProcessingStarted { + #[prost(message, optional, tag = "1")] + pub receipt_hash: ::core::option::Option, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ActionReceiptGasReward { + #[prost(message, optional, tag = "1")] + pub tx_hash: ::core::option::Option, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ReceiptProcessing { + #[prost(message, optional, tag = "1")] + pub tx_hash: ::core::option::Option, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct PostponedReceipt { + #[prost(message, optional, tag = "1")] + pub tx_hash: ::core::option::Option, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct UpdatedDelayedReceipts {} + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ValidatorAccountsUpdate {} + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Migration {} + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Cause { + #[prost(message, tag = "1")] + NotWritableToDisk(NotWritableToDisk), + #[prost(message, tag = "2")] + InitialState(InitialState), + #[prost(message, tag = "3")] + TransactionProcessing(TransactionProcessing), + #[prost(message, tag = "4")] + ActionReceiptProcessingStarted(ActionReceiptProcessingStarted), + #[prost(message, tag = "5")] + ActionReceiptGasReward(ActionReceiptGasReward), + #[prost(message, tag = "6")] + ReceiptProcessing(ReceiptProcessing), + #[prost(message, tag = "7")] + PostponedReceipt(PostponedReceipt), + #[prost(message, tag = "8")] + UpdatedDelayedReceipts(UpdatedDelayedReceipts), + #[prost(message, tag = "9")] + ValidatorAccountsUpdate(ValidatorAccountsUpdate), + #[prost(message, tag = "10")] + Migration(Migration), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StateChangeValue { + #[prost(oneof = "state_change_value::Value", tags = "1, 2, 3, 4, 5, 6, 7, 8")] + pub value: ::core::option::Option, +} +/// Nested message and enum types in `StateChangeValue`. +pub mod state_change_value { + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct AccountUpdate { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub account: ::core::option::Option, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct AccountDeletion { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct AccessKeyUpdate { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub public_key: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub access_key: ::core::option::Option, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct AccessKeyDeletion { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub public_key: ::core::option::Option, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct DataUpdate { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub key: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "3")] + pub value: ::prost::alloc::vec::Vec, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct DataDeletion { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub key: ::prost::alloc::vec::Vec, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ContractCodeUpdate { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub code: ::prost::alloc::vec::Vec, + } + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct ContractCodeDeletion { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + } + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Value { + #[prost(message, tag = "1")] + AccountUpdate(AccountUpdate), + #[prost(message, tag = "2")] + AccountDeletion(AccountDeletion), + #[prost(message, tag = "3")] + AccessKeyUpdate(AccessKeyUpdate), + #[prost(message, tag = "4")] + AccessKeyDeletion(AccessKeyDeletion), + #[prost(message, tag = "5")] + DataUpdate(DataUpdate), + #[prost(message, tag = "6")] + DataDeletion(DataDeletion), + #[prost(message, tag = "7")] + ContractCodeUpdate(ContractCodeUpdate), + #[prost(message, tag = "8")] + ContractDeletion(ContractCodeDeletion), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Account { + #[prost(message, optional, tag = "1")] + pub amount: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub locked: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub code_hash: ::core::option::Option, + #[prost(uint64, tag = "4")] + pub storage_usage: u64, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockHeader { + #[prost(uint64, tag = "1")] + pub height: u64, + #[prost(uint64, tag = "2")] + pub prev_height: u64, + #[prost(message, optional, tag = "3")] + pub epoch_id: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub next_epoch_id: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub hash: ::core::option::Option, + #[prost(message, optional, tag = "6")] + pub prev_hash: ::core::option::Option, + #[prost(message, optional, tag = "7")] + pub prev_state_root: ::core::option::Option, + #[prost(message, optional, tag = "8")] + pub chunk_receipts_root: ::core::option::Option, + #[prost(message, optional, tag = "9")] + pub chunk_headers_root: ::core::option::Option, + #[prost(message, optional, tag = "10")] + pub chunk_tx_root: ::core::option::Option, + #[prost(message, optional, tag = "11")] + pub outcome_root: ::core::option::Option, + #[prost(uint64, tag = "12")] + pub chunks_included: u64, + #[prost(message, optional, tag = "13")] + pub challenges_root: ::core::option::Option, + #[prost(uint64, tag = "14")] + pub timestamp: u64, + #[prost(uint64, tag = "15")] + pub timestamp_nanosec: u64, + #[prost(message, optional, tag = "16")] + pub random_value: ::core::option::Option, + #[prost(message, repeated, tag = "17")] + pub validator_proposals: ::prost::alloc::vec::Vec, + #[prost(bool, repeated, tag = "18")] + pub chunk_mask: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "19")] + pub gas_price: ::core::option::Option, + #[prost(uint64, tag = "20")] + pub block_ordinal: u64, + #[prost(message, optional, tag = "21")] + pub total_supply: ::core::option::Option, + #[prost(message, repeated, tag = "22")] + pub challenges_result: ::prost::alloc::vec::Vec, + #[prost(uint64, tag = "23")] + pub last_final_block_height: u64, + #[prost(message, optional, tag = "24")] + pub last_final_block: ::core::option::Option, + #[prost(uint64, tag = "25")] + pub last_ds_final_block_height: u64, + #[prost(message, optional, tag = "26")] + pub last_ds_final_block: ::core::option::Option, + #[prost(message, optional, tag = "27")] + pub next_bp_hash: ::core::option::Option, + #[prost(message, optional, tag = "28")] + pub block_merkle_root: ::core::option::Option, + #[prost(bytes = "vec", tag = "29")] + pub epoch_sync_data_hash: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "30")] + pub approvals: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "31")] + pub signature: ::core::option::Option, + #[prost(uint32, tag = "32")] + pub latest_protocol_version: u32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BigInt { + #[prost(bytes = "vec", tag = "1")] + pub bytes: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CryptoHash { + #[prost(bytes = "vec", tag = "1")] + pub bytes: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Signature { + #[prost(enumeration = "CurveKind", tag = "1")] + pub r#type: i32, + #[prost(bytes = "vec", tag = "2")] + pub bytes: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PublicKey { + #[prost(enumeration = "CurveKind", tag = "1")] + pub r#type: i32, + #[prost(bytes = "vec", tag = "2")] + pub bytes: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ValidatorStake { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub public_key: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub stake: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SlashedValidator { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(bool, tag = "2")] + pub is_double_sign: bool, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ChunkHeader { + #[prost(bytes = "vec", tag = "1")] + pub chunk_hash: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "2")] + pub prev_block_hash: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "3")] + pub outcome_root: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "4")] + pub prev_state_root: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "5")] + pub encoded_merkle_root: ::prost::alloc::vec::Vec, + #[prost(uint64, tag = "6")] + pub encoded_length: u64, + #[prost(uint64, tag = "7")] + pub height_created: u64, + #[prost(uint64, tag = "8")] + pub height_included: u64, + #[prost(uint64, tag = "9")] + pub shard_id: u64, + #[prost(uint64, tag = "10")] + pub gas_used: u64, + #[prost(uint64, tag = "11")] + pub gas_limit: u64, + #[prost(message, optional, tag = "12")] + pub validator_reward: ::core::option::Option, + #[prost(message, optional, tag = "13")] + pub balance_burnt: ::core::option::Option, + #[prost(bytes = "vec", tag = "14")] + pub outgoing_receipts_root: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "15")] + pub tx_root: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "16")] + pub validator_proposals: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "17")] + pub signature: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerShard { + #[prost(uint64, tag = "1")] + pub shard_id: u64, + #[prost(message, optional, tag = "2")] + pub chunk: ::core::option::Option, + #[prost(message, repeated, tag = "3")] + pub receipt_execution_outcomes: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerExecutionOutcomeWithReceipt { + #[prost(message, optional, tag = "1")] + pub execution_outcome: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub receipt: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerChunk { + #[prost(string, tag = "1")] + pub author: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub header: ::core::option::Option, + #[prost(message, repeated, tag = "3")] + pub transactions: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "4")] + pub receipts: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerTransactionWithOutcome { + #[prost(message, optional, tag = "1")] + pub transaction: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub outcome: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignedTransaction { + #[prost(string, tag = "1")] + pub signer_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub public_key: ::core::option::Option, + #[prost(uint64, tag = "3")] + pub nonce: u64, + #[prost(string, tag = "4")] + pub receiver_id: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "5")] + pub actions: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "6")] + pub signature: ::core::option::Option, + #[prost(message, optional, tag = "7")] + pub hash: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IndexerExecutionOutcomeWithOptionalReceipt { + #[prost(message, optional, tag = "1")] + pub execution_outcome: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub receipt: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Receipt { + #[prost(string, tag = "1")] + pub predecessor_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub receiver_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "3")] + pub receipt_id: ::core::option::Option, + #[prost(oneof = "receipt::Receipt", tags = "10, 11")] + pub receipt: ::core::option::Option, +} +/// Nested message and enum types in `Receipt`. +pub mod receipt { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Receipt { + #[prost(message, tag = "10")] + Action(super::ReceiptAction), + #[prost(message, tag = "11")] + Data(super::ReceiptData), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ReceiptData { + #[prost(message, optional, tag = "1")] + pub data_id: ::core::option::Option, + #[prost(bytes = "vec", tag = "2")] + pub data: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ReceiptAction { + #[prost(string, tag = "1")] + pub signer_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub signer_public_key: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub gas_price: ::core::option::Option, + #[prost(message, repeated, tag = "4")] + pub output_data_receivers: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "5")] + pub input_data_ids: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "6")] + pub actions: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DataReceiver { + #[prost(message, optional, tag = "1")] + pub data_id: ::core::option::Option, + #[prost(string, tag = "2")] + pub receiver_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExecutionOutcomeWithId { + #[prost(message, optional, tag = "1")] + pub proof: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub block_hash: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub id: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub outcome: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExecutionOutcome { + #[prost(string, repeated, tag = "1")] + pub logs: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(message, repeated, tag = "2")] + pub receipt_ids: ::prost::alloc::vec::Vec, + #[prost(uint64, tag = "3")] + pub gas_burnt: u64, + #[prost(message, optional, tag = "4")] + pub tokens_burnt: ::core::option::Option, + #[prost(string, tag = "5")] + pub executor_id: ::prost::alloc::string::String, + #[prost(enumeration = "ExecutionMetadata", tag = "6")] + pub metadata: i32, + #[prost(oneof = "execution_outcome::Status", tags = "20, 21, 22, 23")] + pub status: ::core::option::Option, +} +/// Nested message and enum types in `ExecutionOutcome`. +pub mod execution_outcome { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Status { + #[prost(message, tag = "20")] + Unknown(super::UnknownExecutionStatus), + #[prost(message, tag = "21")] + Failure(super::FailureExecutionStatus), + #[prost(message, tag = "22")] + SuccessValue(super::SuccessValueExecutionStatus), + #[prost(message, tag = "23")] + SuccessReceiptId(super::SuccessReceiptIdExecutionStatus), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SuccessValueExecutionStatus { + #[prost(bytes = "vec", tag = "1")] + pub value: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SuccessReceiptIdExecutionStatus { + #[prost(message, optional, tag = "1")] + pub id: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UnknownExecutionStatus {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FailureExecutionStatus { + #[prost(oneof = "failure_execution_status::Failure", tags = "1, 2")] + pub failure: ::core::option::Option, +} +/// Nested message and enum types in `FailureExecutionStatus`. +pub mod failure_execution_status { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Failure { + #[prost(message, tag = "1")] + ActionError(super::ActionError), + #[prost(enumeration = "super::InvalidTxError", tag = "2")] + InvalidTxError(i32), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ActionError { + #[prost(uint64, tag = "1")] + pub index: u64, + #[prost( + oneof = "action_error::Kind", + tags = "21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36" + )] + pub kind: ::core::option::Option, +} +/// Nested message and enum types in `ActionError`. +pub mod action_error { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Kind { + #[prost(message, tag = "21")] + AccountAlreadyExist(super::AccountAlreadyExistsErrorKind), + #[prost(message, tag = "22")] + AccountDoesNotExist(super::AccountDoesNotExistErrorKind), + #[prost(message, tag = "23")] + CreateAccountOnlyByRegistrar(super::CreateAccountOnlyByRegistrarErrorKind), + #[prost(message, tag = "24")] + CreateAccountNotAllowed(super::CreateAccountNotAllowedErrorKind), + #[prost(message, tag = "25")] + ActorNoPermission(super::ActorNoPermissionErrorKind), + #[prost(message, tag = "26")] + DeleteKeyDoesNotExist(super::DeleteKeyDoesNotExistErrorKind), + #[prost(message, tag = "27")] + AddKeyAlreadyExists(super::AddKeyAlreadyExistsErrorKind), + #[prost(message, tag = "28")] + DeleteAccountStaking(super::DeleteAccountStakingErrorKind), + #[prost(message, tag = "29")] + LackBalanceForState(super::LackBalanceForStateErrorKind), + #[prost(message, tag = "30")] + TriesToUnstake(super::TriesToUnstakeErrorKind), + #[prost(message, tag = "31")] + TriesToStake(super::TriesToStakeErrorKind), + #[prost(message, tag = "32")] + InsufficientStake(super::InsufficientStakeErrorKind), + #[prost(message, tag = "33")] + FunctionCall(super::FunctionCallErrorKind), + #[prost(message, tag = "34")] + NewReceiptValidation(super::NewReceiptValidationErrorKind), + #[prost(message, tag = "35")] + OnlyImplicitAccountCreationAllowed(super::OnlyImplicitAccountCreationAllowedErrorKind), + #[prost(message, tag = "36")] + DeleteAccountWithLargeState(super::DeleteAccountWithLargeStateErrorKind), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountAlreadyExistsErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountDoesNotExistErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, +} +//// A top-level account ID can only be created by registrar. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateAccountOnlyByRegistrarErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub registrar_account_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub predecessor_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateAccountNotAllowedErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub predecessor_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ActorNoPermissionErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub actor_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeleteKeyDoesNotExistErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub public_key: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddKeyAlreadyExistsErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub public_key: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeleteAccountStakingErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LackBalanceForStateErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub balance: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TriesToUnstakeErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TriesToStakeErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub stake: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub locked: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub balance: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InsufficientStakeErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub stake: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub minimum_stake: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FunctionCallErrorKind { + #[prost(enumeration = "FunctionCallErrorSer", tag = "1")] + pub error: i32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NewReceiptValidationErrorKind { + #[prost(enumeration = "ReceiptValidationError", tag = "1")] + pub error: i32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct OnlyImplicitAccountCreationAllowedErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeleteAccountWithLargeStateErrorKind { + #[prost(string, tag = "1")] + pub account_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MerklePath { + #[prost(message, repeated, tag = "1")] + pub path: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MerklePathItem { + #[prost(message, optional, tag = "1")] + pub hash: ::core::option::Option, + #[prost(enumeration = "Direction", tag = "2")] + pub direction: i32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Action { + #[prost(oneof = "action::Action", tags = "1, 2, 3, 4, 5, 6, 7, 8")] + pub action: ::core::option::Option, +} +/// Nested message and enum types in `Action`. +pub mod action { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Action { + #[prost(message, tag = "1")] + CreateAccount(super::CreateAccountAction), + #[prost(message, tag = "2")] + DeployContract(super::DeployContractAction), + #[prost(message, tag = "3")] + FunctionCall(super::FunctionCallAction), + #[prost(message, tag = "4")] + Transfer(super::TransferAction), + #[prost(message, tag = "5")] + Stake(super::StakeAction), + #[prost(message, tag = "6")] + AddKey(super::AddKeyAction), + #[prost(message, tag = "7")] + DeleteKey(super::DeleteKeyAction), + #[prost(message, tag = "8")] + DeleteAccount(super::DeleteAccountAction), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateAccountAction {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeployContractAction { + #[prost(bytes = "vec", tag = "1")] + pub code: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FunctionCallAction { + #[prost(string, tag = "1")] + pub method_name: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub args: ::prost::alloc::vec::Vec, + #[prost(uint64, tag = "3")] + pub gas: u64, + #[prost(message, optional, tag = "4")] + pub deposit: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransferAction { + #[prost(message, optional, tag = "1")] + pub deposit: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct StakeAction { + #[prost(message, optional, tag = "1")] + pub stake: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub public_key: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AddKeyAction { + #[prost(message, optional, tag = "1")] + pub public_key: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub access_key: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeleteKeyAction { + #[prost(message, optional, tag = "1")] + pub public_key: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeleteAccountAction { + #[prost(string, tag = "1")] + pub beneficiary_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccessKey { + #[prost(uint64, tag = "1")] + pub nonce: u64, + #[prost(message, optional, tag = "2")] + pub permission: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccessKeyPermission { + #[prost(oneof = "access_key_permission::Permission", tags = "1, 2")] + pub permission: ::core::option::Option, +} +/// Nested message and enum types in `AccessKeyPermission`. +pub mod access_key_permission { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Permission { + #[prost(message, tag = "1")] + FunctionCall(super::FunctionCallPermission), + #[prost(message, tag = "2")] + FullAccess(super::FullAccessPermission), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FunctionCallPermission { + #[prost(message, optional, tag = "1")] + pub allowance: ::core::option::Option, + #[prost(string, tag = "2")] + pub receiver_id: ::prost::alloc::string::String, + #[prost(string, repeated, tag = "3")] + pub method_names: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FullAccessPermission {} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum CurveKind { + Ed25519 = 0, + Secp256k1 = 1, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ExecutionMetadata { + V1 = 0, +} +///todo: add more detail? +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum FunctionCallErrorSer { + CompilationError = 0, + LinkError = 1, + MethodResolveError = 2, + WasmTrap = 3, + WasmUnknownError = 4, + HostError = 5, + EvmError = 6, + ExecutionError = 7, +} +///todo: add more detail? +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ReceiptValidationError { + InvalidPredecessorId = 0, + InvalidReceiverAccountId = 1, + InvalidSignerAccountId = 2, + InvalidDataReceiverId = 3, + ReturnedValueLengthExceeded = 4, + NumberInputDataDependenciesExceeded = 5, + ActionsValidationError = 6, +} +///todo: add more detail? +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum InvalidTxError { + InvalidAccessKeyError = 0, + InvalidSignerId = 1, + SignerDoesNotExist = 2, + InvalidNonce = 3, + NonceTooLarge = 4, + InvalidReceiverId = 5, + InvalidSignature = 6, + NotEnoughBalance = 7, + LackBalanceForState = 8, + CostOverflow = 9, + InvalidChain = 10, + Expired = 11, + ActionsValidation = 12, + TransactionSizeExceeded = 13, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum Direction { + Left = 0, + Right = 1, +} diff --git a/chain/arweave/src/runtime/abi.rs b/chain/arweave/src/runtime/abi.rs new file mode 100644 index 00000000000..fdd3be12e6f --- /dev/null +++ b/chain/arweave/src/runtime/abi.rs @@ -0,0 +1,637 @@ +use crate::codec; +use crate::trigger::ReceiptWithOutcome; +use graph::anyhow::anyhow; +use graph::runtime::gas::GasCounter; +use graph::runtime::{asc_new, AscHeap, AscPtr, DeterministicHostError, ToAscObj}; +use graph_runtime_wasm::asc_abi::class::{Array, AscEnum, EnumPayload, Uint8Array}; + +pub(crate) use super::generated::*; + +impl ToAscObj for codec::Block { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscBlock { + author: asc_new(heap, &self.author, gas)?, + header: asc_new(heap, self.header(), gas)?, + chunks: asc_new(heap, &self.chunk_headers, gas)?, + }) + } +} + +impl ToAscObj for codec::BlockHeader { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let chunk_mask = Array::new(self.chunk_mask.as_ref(), heap, gas)?; + + Ok(AscBlockHeader { + height: self.height, + prev_height: self.prev_height, + epoch_id: asc_new(heap, self.epoch_id.as_ref().unwrap(), gas)?, + next_epoch_id: asc_new(heap, self.next_epoch_id.as_ref().unwrap(), gas)?, + hash: asc_new(heap, self.hash.as_ref().unwrap(), gas)?, + prev_hash: asc_new(heap, self.prev_hash.as_ref().unwrap(), gas)?, + prev_state_root: asc_new(heap, self.prev_state_root.as_ref().unwrap(), gas)?, + chunk_receipts_root: asc_new(heap, self.chunk_receipts_root.as_ref().unwrap(), gas)?, + chunk_headers_root: asc_new(heap, self.chunk_headers_root.as_ref().unwrap(), gas)?, + chunk_tx_root: asc_new(heap, self.chunk_tx_root.as_ref().unwrap(), gas)?, + outcome_root: asc_new(heap, self.outcome_root.as_ref().unwrap(), gas)?, + chunks_included: self.chunks_included, + challenges_root: asc_new(heap, self.challenges_root.as_ref().unwrap(), gas)?, + timestamp_nanosec: self.timestamp_nanosec, + random_value: asc_new(heap, self.random_value.as_ref().unwrap(), gas)?, + validator_proposals: asc_new(heap, &self.validator_proposals, gas)?, + chunk_mask: AscPtr::alloc_obj(chunk_mask, heap, gas)?, + gas_price: asc_new(heap, self.gas_price.as_ref().unwrap(), gas)?, + block_ordinal: self.block_ordinal, + total_supply: asc_new(heap, self.total_supply.as_ref().unwrap(), gas)?, + challenges_result: asc_new(heap, &self.challenges_result, gas)?, + last_final_block: asc_new(heap, self.last_final_block.as_ref().unwrap(), gas)?, + last_ds_final_block: asc_new(heap, self.last_ds_final_block.as_ref().unwrap(), gas)?, + next_bp_hash: asc_new(heap, self.next_bp_hash.as_ref().unwrap(), gas)?, + block_merkle_root: asc_new(heap, self.block_merkle_root.as_ref().unwrap(), gas)?, + epoch_sync_data_hash: asc_new(heap, self.epoch_sync_data_hash.as_slice(), gas)?, + approvals: asc_new(heap, &self.approvals, gas)?, + signature: asc_new(heap, &self.signature.as_ref().unwrap(), gas)?, + latest_protocol_version: self.latest_protocol_version, + }) + } +} + +impl ToAscObj for codec::ChunkHeader { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscChunkHeader { + chunk_hash: asc_new(heap, self.chunk_hash.as_slice(), gas)?, + signature: asc_new(heap, &self.signature.as_ref().unwrap(), gas)?, + prev_block_hash: asc_new(heap, self.prev_block_hash.as_slice(), gas)?, + prev_state_root: asc_new(heap, self.prev_state_root.as_slice(), gas)?, + encoded_merkle_root: asc_new(heap, self.encoded_merkle_root.as_slice(), gas)?, + encoded_length: self.encoded_length, + height_created: self.height_created, + height_included: self.height_included, + shard_id: self.shard_id, + gas_used: self.gas_used, + gas_limit: self.gas_limit, + balance_burnt: asc_new(heap, self.balance_burnt.as_ref().unwrap(), gas)?, + outgoing_receipts_root: asc_new(heap, self.outgoing_receipts_root.as_slice(), gas)?, + tx_root: asc_new(heap, self.tx_root.as_slice(), gas)?, + validator_proposals: asc_new(heap, &self.validator_proposals, gas)?, + + _padding: 0, + }) + } +} + +impl ToAscObj for Vec { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); + let content = content?; + Ok(AscChunkHeaderArray(Array::new(&*content, heap, gas)?)) + } +} + +impl ToAscObj for ReceiptWithOutcome { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscReceiptWithOutcome { + outcome: asc_new(heap, &self.outcome, gas)?, + receipt: asc_new(heap, &self.receipt, gas)?, + block: asc_new(heap, self.block.as_ref(), gas)?, + }) + } +} + +impl ToAscObj for codec::Receipt { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let action = match self.receipt.as_ref().unwrap() { + codec::receipt::Receipt::Action(action) => action, + codec::receipt::Receipt::Data(_) => { + return Err(DeterministicHostError::from(anyhow!( + "Data receipt are now allowed" + ))); + } + }; + + Ok(AscActionReceipt { + id: asc_new(heap, &self.receipt_id.as_ref().unwrap(), gas)?, + predecessor_id: asc_new(heap, &self.predecessor_id, gas)?, + receiver_id: asc_new(heap, &self.receiver_id, gas)?, + signer_id: asc_new(heap, &action.signer_id, gas)?, + signer_public_key: asc_new(heap, action.signer_public_key.as_ref().unwrap(), gas)?, + gas_price: asc_new(heap, action.gas_price.as_ref().unwrap(), gas)?, + output_data_receivers: asc_new(heap, &action.output_data_receivers, gas)?, + input_data_ids: asc_new(heap, &action.input_data_ids, gas)?, + actions: asc_new(heap, &action.actions, gas)?, + }) + } +} + +impl ToAscObj for codec::Action { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let (kind, payload) = match self.action.as_ref().unwrap() { + codec::action::Action::CreateAccount(action) => ( + AscActionKind::CreateAccount, + asc_new(heap, action, gas)?.to_payload(), + ), + codec::action::Action::DeployContract(action) => ( + AscActionKind::DeployContract, + asc_new(heap, action, gas)?.to_payload(), + ), + codec::action::Action::FunctionCall(action) => ( + AscActionKind::FunctionCall, + asc_new(heap, action, gas)?.to_payload(), + ), + codec::action::Action::Transfer(action) => ( + AscActionKind::Transfer, + asc_new(heap, action, gas)?.to_payload(), + ), + codec::action::Action::Stake(action) => ( + AscActionKind::Stake, + asc_new(heap, action, gas)?.to_payload(), + ), + codec::action::Action::AddKey(action) => ( + AscActionKind::AddKey, + asc_new(heap, action, gas)?.to_payload(), + ), + codec::action::Action::DeleteKey(action) => ( + AscActionKind::DeleteKey, + asc_new(heap, action, gas)?.to_payload(), + ), + codec::action::Action::DeleteAccount(action) => ( + AscActionKind::DeleteAccount, + asc_new(heap, action, gas)?.to_payload(), + ), + }; + + Ok(AscActionEnum(AscEnum { + kind, + _padding: 0, + payload: EnumPayload(payload), + })) + } +} + +impl ToAscObj for Vec { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); + let content = content?; + Ok(AscActionEnumArray(Array::new(&*content, heap, gas)?)) + } +} + +impl ToAscObj for codec::CreateAccountAction { + fn to_asc_obj( + &self, + _heap: &mut H, + _gas: &GasCounter, + ) -> Result { + Ok(AscCreateAccountAction {}) + } +} + +impl ToAscObj for codec::DeployContractAction { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscDeployContractAction { + code: asc_new(heap, self.code.as_slice(), gas)?, + }) + } +} + +impl ToAscObj for codec::FunctionCallAction { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscFunctionCallAction { + method_name: asc_new(heap, &self.method_name, gas)?, + args: asc_new(heap, self.args.as_slice(), gas)?, + gas: self.gas, + deposit: asc_new(heap, self.deposit.as_ref().unwrap(), gas)?, + _padding: 0, + }) + } +} + +impl ToAscObj for codec::TransferAction { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscTransferAction { + deposit: asc_new(heap, self.deposit.as_ref().unwrap(), gas)?, + }) + } +} + +impl ToAscObj for codec::StakeAction { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscStakeAction { + stake: asc_new(heap, self.stake.as_ref().unwrap(), gas)?, + public_key: asc_new(heap, self.public_key.as_ref().unwrap(), gas)?, + }) + } +} + +impl ToAscObj for codec::AddKeyAction { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscAddKeyAction { + public_key: asc_new(heap, self.public_key.as_ref().unwrap(), gas)?, + access_key: asc_new(heap, self.access_key.as_ref().unwrap(), gas)?, + }) + } +} + +impl ToAscObj for codec::AccessKey { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscAccessKey { + nonce: self.nonce, + permission: asc_new(heap, self.permission.as_ref().unwrap(), gas)?, + _padding: 0, + }) + } +} + +impl ToAscObj for codec::AccessKeyPermission { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let (kind, payload) = match self.permission.as_ref().unwrap() { + codec::access_key_permission::Permission::FunctionCall(permission) => ( + AscAccessKeyPermissionKind::FunctionCall, + asc_new(heap, permission, gas)?.to_payload(), + ), + codec::access_key_permission::Permission::FullAccess(permission) => ( + AscAccessKeyPermissionKind::FullAccess, + asc_new(heap, permission, gas)?.to_payload(), + ), + }; + + Ok(AscAccessKeyPermissionEnum(AscEnum { + _padding: 0, + kind, + payload: EnumPayload(payload), + })) + } +} + +impl ToAscObj for codec::FunctionCallPermission { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscFunctionCallPermission { + // The `allowance` field is one of the few fields that can actually be None for real + allowance: match self.allowance.as_ref() { + Some(allowance) => asc_new(heap, allowance, gas)?, + None => AscPtr::null(), + }, + receiver_id: asc_new(heap, &self.receiver_id, gas)?, + method_names: asc_new(heap, &self.method_names, gas)?, + }) + } +} + +impl ToAscObj for codec::FullAccessPermission { + fn to_asc_obj( + &self, + _heap: &mut H, + _gas: &GasCounter, + ) -> Result { + Ok(AscFullAccessPermission {}) + } +} + +impl ToAscObj for codec::DeleteKeyAction { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscDeleteKeyAction { + public_key: asc_new(heap, self.public_key.as_ref().unwrap(), gas)?, + }) + } +} + +impl ToAscObj for codec::DeleteAccountAction { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscDeleteAccountAction { + beneficiary_id: asc_new(heap, &self.beneficiary_id, gas)?, + }) + } +} + +impl ToAscObj for codec::DataReceiver { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscDataReceiver { + data_id: asc_new(heap, self.data_id.as_ref().unwrap(), gas)?, + receiver_id: asc_new(heap, &self.receiver_id, gas)?, + }) + } +} + +impl ToAscObj for Vec { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); + let content = content?; + Ok(AscDataReceiverArray(Array::new(&*content, heap, gas)?)) + } +} + +impl ToAscObj for codec::ExecutionOutcomeWithId { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let outcome = self.outcome.as_ref().unwrap(); + + Ok(AscExecutionOutcome { + proof: asc_new(heap, &self.proof.as_ref().unwrap().path, gas)?, + block_hash: asc_new(heap, self.block_hash.as_ref().unwrap(), gas)?, + id: asc_new(heap, self.id.as_ref().unwrap(), gas)?, + logs: asc_new(heap, &outcome.logs, gas)?, + receipt_ids: asc_new(heap, &outcome.receipt_ids, gas)?, + gas_burnt: outcome.gas_burnt, + tokens_burnt: asc_new(heap, outcome.tokens_burnt.as_ref().unwrap(), gas)?, + executor_id: asc_new(heap, &outcome.executor_id, gas)?, + status: asc_new(heap, outcome.status.as_ref().unwrap(), gas)?, + }) + } +} + +impl ToAscObj for codec::execution_outcome::Status { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let (kind, payload) = match self { + codec::execution_outcome::Status::SuccessValue(value) => { + let bytes = &value.value; + + ( + AscSuccessStatusKind::Value, + asc_new(heap, bytes.as_slice(), gas)?.to_payload(), + ) + } + codec::execution_outcome::Status::SuccessReceiptId(receipt_id) => ( + AscSuccessStatusKind::ReceiptId, + asc_new(heap, receipt_id.id.as_ref().unwrap(), gas)?.to_payload(), + ), + codec::execution_outcome::Status::Failure(_) => { + return Err(DeterministicHostError::from(anyhow!( + "Failure execution status are not allowed" + ))); + } + codec::execution_outcome::Status::Unknown(_) => { + return Err(DeterministicHostError::from(anyhow!( + "Unknown execution status are not allowed" + ))); + } + }; + + Ok(AscSuccessStatusEnum(AscEnum { + _padding: 0, + kind, + payload: EnumPayload(payload), + })) + } +} + +impl ToAscObj for codec::MerklePathItem { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscMerklePathItem { + hash: asc_new(heap, self.hash.as_ref().unwrap(), gas)?, + direction: match self.direction { + 0 => AscDirection::Left, + 1 => AscDirection::Right, + x => { + return Err(DeterministicHostError::from(anyhow!( + "Invalid direction value {}", + x + ))) + } + }, + }) + } +} + +impl ToAscObj for Vec { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); + let content = content?; + Ok(AscMerklePathItemArray(Array::new(&*content, heap, gas)?)) + } +} + +impl ToAscObj for codec::Signature { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscSignature { + kind: match self.r#type { + 0 => 0, + 1 => 1, + value => { + return Err(DeterministicHostError::from(anyhow!( + "Invalid signature type {}", + value, + ))) + } + }, + bytes: asc_new(heap, self.bytes.as_slice(), gas)?, + }) + } +} + +impl ToAscObj for Vec { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); + let content = content?; + Ok(AscSignatureArray(Array::new(&*content, heap, gas)?)) + } +} + +impl ToAscObj for codec::PublicKey { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscPublicKey { + kind: match self.r#type { + 0 => 0, + 1 => 1, + value => { + return Err(DeterministicHostError::from(anyhow!( + "Invalid public key type {}", + value, + ))) + } + }, + bytes: asc_new(heap, self.bytes.as_slice(), gas)?, + }) + } +} + +impl ToAscObj for codec::ValidatorStake { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscValidatorStake { + account_id: asc_new(heap, &self.account_id, gas)?, + public_key: asc_new(heap, self.public_key.as_ref().unwrap(), gas)?, + stake: asc_new(heap, self.stake.as_ref().unwrap(), gas)?, + }) + } +} + +impl ToAscObj for Vec { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); + let content = content?; + Ok(AscValidatorStakeArray(Array::new(&*content, heap, gas)?)) + } +} + +impl ToAscObj for codec::SlashedValidator { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscSlashedValidator { + account_id: asc_new(heap, &self.account_id, gas)?, + is_double_sign: self.is_double_sign, + }) + } +} + +impl ToAscObj for Vec { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); + let content = content?; + Ok(AscSlashedValidatorArray(Array::new(&*content, heap, gas)?)) + } +} + +impl ToAscObj for codec::CryptoHash { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + self.bytes.to_asc_obj(heap, gas) + } +} + +impl ToAscObj for Vec { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); + let content = content?; + Ok(AscCryptoHashArray(Array::new(&*content, heap, gas)?)) + } +} + +impl ToAscObj for codec::BigInt { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + // Bytes are reversed to align with BigInt bytes endianess + let reversed: Vec = self.bytes.iter().rev().map(|x| *x).collect(); + + reversed.to_asc_obj(heap, gas) + } +} diff --git a/chain/arweave/src/runtime/generated.rs b/chain/arweave/src/runtime/generated.rs new file mode 100644 index 00000000000..f1d7e0bdb02 --- /dev/null +++ b/chain/arweave/src/runtime/generated.rs @@ -0,0 +1,620 @@ +use graph::runtime::{ + AscIndexId, AscPtr, AscType, AscValue, DeterministicHostError, IndexForAscTypeId, +}; +use graph::semver::Version; +use graph_runtime_derive::AscType; +use graph_runtime_wasm::asc_abi::class::{Array, AscBigInt, AscEnum, AscString, Uint8Array}; + +pub(crate) type AscCryptoHash = Uint8Array; +pub(crate) type AscAccountId = AscString; +pub(crate) type AscBlockHeight = u64; +pub(crate) type AscBalance = AscBigInt; +pub(crate) type AscGas = u64; +pub(crate) type AscShardId = u64; +pub(crate) type AscNumBlocks = u64; +pub(crate) type AscProtocolVersion = u32; + +pub struct AscDataReceiverArray(pub(crate) Array>); + +impl AscType for AscDataReceiverArray { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscDataReceiverArray { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayDataReceiver; +} + +pub struct AscCryptoHashArray(pub(crate) Array>); + +impl AscType for AscCryptoHashArray { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscCryptoHashArray { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayCryptoHash; +} + +pub struct AscActionEnumArray(pub(crate) Array>); + +impl AscType for AscActionEnumArray { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscActionEnumArray { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayActionEnum; +} + +pub struct AscMerklePathItemArray(pub(crate) Array>); + +impl AscType for AscMerklePathItemArray { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscMerklePathItemArray { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayMerklePathItem; +} + +pub struct AscValidatorStakeArray(pub(crate) Array>); + +impl AscType for AscValidatorStakeArray { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscValidatorStakeArray { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayValidatorStake; +} + +pub struct AscSlashedValidatorArray(pub(crate) Array>); + +impl AscType for AscSlashedValidatorArray { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscSlashedValidatorArray { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArraySlashedValidator; +} + +pub struct AscSignatureArray(pub(crate) Array>); + +impl AscType for AscSignatureArray { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscSignatureArray { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArraySignature; +} + +pub struct AscChunkHeaderArray(pub(crate) Array>); + +impl AscType for AscChunkHeaderArray { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscChunkHeaderArray { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayChunkHeader; +} + +pub struct AscAccessKeyPermissionEnum(pub(crate) AscEnum); + +impl AscType for AscAccessKeyPermissionEnum { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(AscEnum::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscAccessKeyPermissionEnum { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearAccessKeyPermissionEnum; +} + +pub struct AscActionEnum(pub(crate) AscEnum); + +impl AscType for AscActionEnum { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(AscEnum::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscActionEnum { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearActionEnum; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscPublicKey { + pub kind: u32, + pub bytes: AscPtr, +} + +impl AscIndexId for AscPublicKey { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearPublicKey; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscSignature { + pub kind: u32, + pub bytes: AscPtr, +} + +impl AscIndexId for AscSignature { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearSignature; +} + +#[repr(u32)] +#[derive(AscType, Copy, Clone)] +pub(crate) enum AscAccessKeyPermissionKind { + FunctionCall, + FullAccess, +} + +impl AscValue for AscAccessKeyPermissionKind {} + +impl Default for AscAccessKeyPermissionKind { + fn default() -> Self { + Self::FunctionCall + } +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscFunctionCallPermission { + pub allowance: AscPtr, + pub receiver_id: AscPtr, + pub method_names: AscPtr>>, +} + +impl AscIndexId for AscFunctionCallPermission { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearFunctionCallPermission; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscFullAccessPermission {} + +impl AscIndexId for AscFullAccessPermission { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearFullAccessPermission; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscAccessKey { + pub nonce: u64, + pub permission: AscPtr, + + // It seems that is impossible to correctly order fields in this struct + // so that Rust packs it tighly without padding. So we add 4 bytes of padding + // ourself. + // + // This is a bit problematic because AssemblyScript actually is ok with 12 bytes + // and is fully packed. Seems like a differences between alignment for `repr(C)` and + // AssemblyScript. + pub(crate) _padding: u32, +} + +impl AscIndexId for AscAccessKey { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearAccessKey; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscDataReceiver { + pub data_id: AscPtr, + pub receiver_id: AscPtr, +} + +impl AscIndexId for AscDataReceiver { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearDataReceiver; +} + +#[repr(u32)] +#[derive(AscType, Copy, Clone)] +pub(crate) enum AscActionKind { + CreateAccount, + DeployContract, + FunctionCall, + Transfer, + Stake, + AddKey, + DeleteKey, + DeleteAccount, +} + +impl AscValue for AscActionKind {} + +impl Default for AscActionKind { + fn default() -> Self { + Self::CreateAccount + } +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscCreateAccountAction {} + +impl AscIndexId for AscCreateAccountAction { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearCreateAccountAction; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscDeployContractAction { + pub code: AscPtr, +} + +impl AscIndexId for AscDeployContractAction { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearDeployContractAction; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscFunctionCallAction { + pub method_name: AscPtr, + pub args: AscPtr, + pub gas: u64, + pub deposit: AscPtr, + + // It seems that is impossible to correctly order fields in this struct + // so that Rust packs it tighly without padding. So we add 4 bytes of padding + // ourself. + // + // This is a bit problematic because AssemblyScript actually is ok with 20 bytes + // and is fully packed. Seems like a differences between alignment for `repr(C)` and + // AssemblyScript. + pub(crate) _padding: u32, +} + +impl AscIndexId for AscFunctionCallAction { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearFunctionCallAction; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscTransferAction { + pub deposit: AscPtr, +} + +impl AscIndexId for AscTransferAction { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearTransferAction; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscStakeAction { + pub stake: AscPtr, + pub public_key: AscPtr, +} + +impl AscIndexId for AscStakeAction { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearStakeAction; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscAddKeyAction { + pub public_key: AscPtr, + pub access_key: AscPtr, +} + +impl AscIndexId for AscAddKeyAction { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearAddKeyAction; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscDeleteKeyAction { + pub public_key: AscPtr, +} + +impl AscIndexId for AscDeleteKeyAction { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearDeleteKeyAction; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscDeleteAccountAction { + pub beneficiary_id: AscPtr, +} + +impl AscIndexId for AscDeleteAccountAction { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearDeleteAccountAction; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscActionReceipt { + pub predecessor_id: AscPtr, + pub receiver_id: AscPtr, + pub id: AscPtr, + pub signer_id: AscPtr, + pub signer_public_key: AscPtr, + pub gas_price: AscPtr, + pub output_data_receivers: AscPtr, + pub input_data_ids: AscPtr, + pub actions: AscPtr, +} + +impl AscIndexId for AscActionReceipt { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearActionReceipt; +} + +#[repr(u32)] +#[derive(AscType, Copy, Clone)] +pub(crate) enum AscSuccessStatusKind { + Value, + ReceiptId, +} + +impl AscValue for AscSuccessStatusKind {} + +impl Default for AscSuccessStatusKind { + fn default() -> Self { + Self::Value + } +} + +pub struct AscSuccessStatusEnum(pub(crate) AscEnum); + +impl AscType for AscSuccessStatusEnum { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(AscEnum::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscSuccessStatusEnum { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearSuccessStatusEnum; +} + +#[repr(u32)] +#[derive(AscType, Copy, Clone)] +pub(crate) enum AscDirection { + Left, + Right, +} + +impl AscValue for AscDirection {} + +impl Default for AscDirection { + fn default() -> Self { + Self::Left + } +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscMerklePathItem { + pub hash: AscPtr, + pub direction: AscDirection, +} + +impl AscIndexId for AscMerklePathItem { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearMerklePathItem; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscExecutionOutcome { + pub gas_burnt: u64, + pub proof: AscPtr, + pub block_hash: AscPtr, + pub id: AscPtr, + pub logs: AscPtr>>, + pub receipt_ids: AscPtr, + pub tokens_burnt: AscPtr, + pub executor_id: AscPtr, + pub status: AscPtr, +} + +impl AscIndexId for AscExecutionOutcome { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearExecutionOutcome; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscSlashedValidator { + pub account_id: AscPtr, + pub is_double_sign: bool, +} + +impl AscIndexId for AscSlashedValidator { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearSlashedValidator; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscBlockHeader { + pub height: AscBlockHeight, + pub prev_height: AscBlockHeight, + pub block_ordinal: AscNumBlocks, + pub epoch_id: AscPtr, + pub next_epoch_id: AscPtr, + pub chunks_included: u64, + pub hash: AscPtr, + pub prev_hash: AscPtr, + pub timestamp_nanosec: u64, + pub prev_state_root: AscPtr, + pub chunk_receipts_root: AscPtr, + pub chunk_headers_root: AscPtr, + pub chunk_tx_root: AscPtr, + pub outcome_root: AscPtr, + pub challenges_root: AscPtr, + pub random_value: AscPtr, + pub validator_proposals: AscPtr, + pub chunk_mask: AscPtr>, + pub gas_price: AscPtr, + pub total_supply: AscPtr, + pub challenges_result: AscPtr, + pub last_final_block: AscPtr, + pub last_ds_final_block: AscPtr, + pub next_bp_hash: AscPtr, + pub block_merkle_root: AscPtr, + pub epoch_sync_data_hash: AscPtr, + pub approvals: AscPtr, + pub signature: AscPtr, + pub latest_protocol_version: AscProtocolVersion, +} + +impl AscIndexId for AscBlockHeader { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearBlockHeader; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscValidatorStake { + pub account_id: AscPtr, + pub public_key: AscPtr, + pub stake: AscPtr, +} + +impl AscIndexId for AscValidatorStake { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearValidatorStake; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscChunkHeader { + pub encoded_length: u64, + pub gas_used: AscGas, + pub gas_limit: AscGas, + pub shard_id: AscShardId, + pub height_created: AscBlockHeight, + pub height_included: AscBlockHeight, + pub chunk_hash: AscPtr, + pub signature: AscPtr, + pub prev_block_hash: AscPtr, + pub prev_state_root: AscPtr, + pub encoded_merkle_root: AscPtr, + pub balance_burnt: AscPtr, + pub outgoing_receipts_root: AscPtr, + pub tx_root: AscPtr, + pub validator_proposals: AscPtr, + + // It seems that is impossible to correctly order fields in this struct + // so that Rust packs it tighly without padding. So we add 4 bytes of padding + // ourself. + // + // This is a bit problematic because AssemblyScript actually is ok with 84 bytes + // and is fully packed. Seems like a differences between alignment for `repr(C)` and + // AssemblyScript. + pub(crate) _padding: u32, +} + +impl AscIndexId for AscChunkHeader { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearChunkHeader; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscBlock { + pub author: AscPtr, + pub header: AscPtr, + pub chunks: AscPtr, +} + +impl AscIndexId for AscBlock { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearBlock; +} + +#[repr(C)] +#[derive(AscType)] +pub(crate) struct AscReceiptWithOutcome { + pub outcome: AscPtr, + pub receipt: AscPtr, + pub block: AscPtr, +} + +impl AscIndexId for AscReceiptWithOutcome { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearReceiptWithOutcome; +} diff --git a/chain/arweave/src/runtime/mod.rs b/chain/arweave/src/runtime/mod.rs new file mode 100644 index 00000000000..f44391caffd --- /dev/null +++ b/chain/arweave/src/runtime/mod.rs @@ -0,0 +1,6 @@ +pub use runtime_adapter::RuntimeAdapter; + +pub mod abi; +pub mod runtime_adapter; + +mod generated; diff --git a/chain/arweave/src/runtime/runtime_adapter.rs b/chain/arweave/src/runtime/runtime_adapter.rs new file mode 100644 index 00000000000..c5fa9e15059 --- /dev/null +++ b/chain/arweave/src/runtime/runtime_adapter.rs @@ -0,0 +1,11 @@ +use crate::{data_source::DataSource, Chain}; +use blockchain::HostFn; +use graph::{anyhow::Error, blockchain}; + +pub struct RuntimeAdapter {} + +impl blockchain::RuntimeAdapter for RuntimeAdapter { + fn host_fns(&self, _ds: &DataSource) -> Result, Error> { + Ok(vec![]) + } +} diff --git a/chain/arweave/src/trigger.rs b/chain/arweave/src/trigger.rs new file mode 100644 index 00000000000..747fdf1503a --- /dev/null +++ b/chain/arweave/src/trigger.rs @@ -0,0 +1,498 @@ +use graph::blockchain; +use graph::blockchain::Block; +use graph::blockchain::TriggerData; +use graph::cheap_clone::CheapClone; +use graph::prelude::hex; +use graph::prelude::web3::types::H256; +use graph::prelude::BlockNumber; +use graph::runtime::asc_new; +use graph::runtime::gas::GasCounter; +use graph::runtime::AscHeap; +use graph::runtime::AscPtr; +use graph::runtime::DeterministicHostError; +use std::{cmp::Ordering, sync::Arc}; + +use crate::codec; + +// Logging the block is too verbose, so this strips the block from the trigger for Debug. +impl std::fmt::Debug for NearTrigger { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + #[derive(Debug)] + pub enum MappingTriggerWithoutBlock<'a> { + Block, + + Receipt { + outcome: &'a codec::ExecutionOutcomeWithId, + receipt: &'a codec::Receipt, + }, + } + + let trigger_without_block = match self { + NearTrigger::Block(_) => MappingTriggerWithoutBlock::Block, + NearTrigger::Receipt(receipt) => MappingTriggerWithoutBlock::Receipt { + outcome: &receipt.outcome, + receipt: &receipt.receipt, + }, + }; + + write!(f, "{:?}", trigger_without_block) + } +} + +impl blockchain::MappingTrigger for NearTrigger { + fn to_asc_ptr( + self, + heap: &mut H, + gas: &GasCounter, + ) -> Result, DeterministicHostError> { + Ok(match self { + NearTrigger::Block(block) => asc_new(heap, block.as_ref(), gas)?.erase(), + NearTrigger::Receipt(receipt) => asc_new(heap, receipt.as_ref(), gas)?.erase(), + }) + } +} + +#[derive(Clone)] +pub enum NearTrigger { + Block(Arc), + Receipt(Arc), +} + +impl CheapClone for NearTrigger { + fn cheap_clone(&self) -> NearTrigger { + match self { + NearTrigger::Block(block) => NearTrigger::Block(block.cheap_clone()), + NearTrigger::Receipt(receipt) => NearTrigger::Receipt(receipt.cheap_clone()), + } + } +} + +impl PartialEq for NearTrigger { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Block(a_ptr), Self::Block(b_ptr)) => a_ptr == b_ptr, + (Self::Receipt(a), Self::Receipt(b)) => a.receipt.receipt_id == b.receipt.receipt_id, + + (Self::Block(_), Self::Receipt(_)) | (Self::Receipt(_), Self::Block(_)) => false, + } + } +} + +impl Eq for NearTrigger {} + +impl NearTrigger { + pub fn block_number(&self) -> BlockNumber { + match self { + NearTrigger::Block(block) => block.number(), + NearTrigger::Receipt(receipt) => receipt.block.number(), + } + } + + pub fn block_hash(&self) -> H256 { + match self { + NearTrigger::Block(block) => block.ptr().hash_as_h256(), + NearTrigger::Receipt(receipt) => receipt.block.ptr().hash_as_h256(), + } + } +} + +impl Ord for NearTrigger { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + // Keep the order when comparing two block triggers + (Self::Block(..), Self::Block(..)) => Ordering::Equal, + + // Block triggers always come last + (Self::Block(..), _) => Ordering::Greater, + (_, Self::Block(..)) => Ordering::Less, + + // Execution outcomes have no intrinsic ordering information, so we keep the order in + // which they are included in the `receipt_execution_outcomes` field of `IndexerShard`. + (Self::Receipt(..), Self::Receipt(..)) => Ordering::Equal, + } + } +} + +impl PartialOrd for NearTrigger { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl TriggerData for NearTrigger { + fn error_context(&self) -> std::string::String { + match self { + NearTrigger::Block(..) => { + format!("Block #{} ({})", self.block_number(), self.block_hash()) + } + NearTrigger::Receipt(receipt) => { + format!( + "receipt id {}, block #{} ({})", + hex::encode(&receipt.receipt.receipt_id.as_ref().unwrap().bytes), + self.block_number(), + self.block_hash() + ) + } + } + } +} + +pub struct ReceiptWithOutcome { + // REVIEW: Do we want to actually also have those two below behind an `Arc` wrapper? + pub outcome: codec::ExecutionOutcomeWithId, + pub receipt: codec::Receipt, + pub block: Arc, +} + +#[cfg(test)] +mod tests { + use std::convert::TryFrom; + + use super::*; + + use graph::{ + anyhow::anyhow, + data::subgraph::API_VERSION_0_0_5, + prelude::{hex, BigInt}, + runtime::gas::GasCounter, + }; + + #[test] + fn block_trigger_to_asc_ptr() { + let mut heap = BytesHeap::new(API_VERSION_0_0_5); + let trigger = NearTrigger::Block(Arc::new(block())); + + let result = + blockchain::MappingTrigger::to_asc_ptr(trigger, &mut heap, &GasCounter::default()); + assert!(result.is_ok()); + } + + #[test] + fn receipt_trigger_to_asc_ptr() { + let mut heap = BytesHeap::new(API_VERSION_0_0_5); + let trigger = NearTrigger::Receipt(Arc::new(ReceiptWithOutcome { + block: Arc::new(block()), + outcome: execution_outcome_with_id().unwrap(), + receipt: receipt().unwrap(), + })); + + let result = + blockchain::MappingTrigger::to_asc_ptr(trigger, &mut heap, &GasCounter::default()); + assert!(result.is_ok()); + } + + fn block() -> codec::Block { + codec::Block { + author: "test".to_string(), + header: Some(codec::BlockHeader { + height: 2, + prev_height: 1, + epoch_id: hash("01"), + next_epoch_id: hash("02"), + hash: hash("01"), + prev_hash: hash("00"), + prev_state_root: hash("bb00010203"), + chunk_receipts_root: hash("bb00010203"), + chunk_headers_root: hash("bb00010203"), + chunk_tx_root: hash("bb00010203"), + outcome_root: hash("cc00010203"), + chunks_included: 1, + challenges_root: hash("aa"), + timestamp: 100, + timestamp_nanosec: 0, + random_value: hash("010203"), + validator_proposals: vec![], + chunk_mask: vec![], + gas_price: big_int(10), + block_ordinal: 0, + total_supply: big_int(1_000), + challenges_result: vec![], + last_final_block: hash("00"), + last_final_block_height: 0, + last_ds_final_block: hash("00"), + last_ds_final_block_height: 0, + next_bp_hash: hash("bb"), + block_merkle_root: hash("aa"), + epoch_sync_data_hash: vec![0x00, 0x01], + approvals: vec![], + signature: signature("00"), + latest_protocol_version: 0, + }), + chunk_headers: vec![chunk_header().unwrap()], + shards: vec![codec::IndexerShard { + shard_id: 0, + chunk: Some(codec::IndexerChunk { + author: "near".to_string(), + header: chunk_header(), + transactions: vec![codec::IndexerTransactionWithOutcome { + transaction: Some(codec::SignedTransaction { + signer_id: "signer".to_string(), + public_key: public_key("aabb"), + nonce: 1, + receiver_id: "receiver".to_string(), + actions: vec![], + signature: signature("ff"), + hash: hash("bb"), + }), + outcome: Some(codec::IndexerExecutionOutcomeWithOptionalReceipt { + execution_outcome: execution_outcome_with_id(), + receipt: receipt(), + }), + }], + receipts: vec![receipt().unwrap()], + }), + receipt_execution_outcomes: vec![codec::IndexerExecutionOutcomeWithReceipt { + execution_outcome: execution_outcome_with_id(), + receipt: receipt(), + }], + }], + state_changes: vec![], + } + } + + fn receipt() -> Option { + Some(codec::Receipt { + predecessor_id: "genesis.near".to_string(), + receiver_id: "near".to_string(), + receipt_id: hash("dead"), + receipt: Some(codec::receipt::Receipt::Action(codec::ReceiptAction { + signer_id: "near".to_string(), + signer_public_key: public_key("aa"), + gas_price: big_int(2), + output_data_receivers: vec![], + input_data_ids: vec![], + actions: vec![ + codec::Action { + action: Some(codec::action::Action::CreateAccount( + codec::CreateAccountAction {}, + )), + }, + codec::Action { + action: Some(codec::action::Action::DeployContract( + codec::DeployContractAction { + code: vec![0x01, 0x02], + }, + )), + }, + codec::Action { + action: Some(codec::action::Action::FunctionCall( + codec::FunctionCallAction { + method_name: "func".to_string(), + args: vec![0x01, 0x02], + gas: 1000, + deposit: big_int(100), + }, + )), + }, + codec::Action { + action: Some(codec::action::Action::Transfer(codec::TransferAction { + deposit: big_int(100), + })), + }, + codec::Action { + action: Some(codec::action::Action::Stake(codec::StakeAction { + stake: big_int(100), + public_key: public_key("aa"), + })), + }, + codec::Action { + action: Some(codec::action::Action::AddKey(codec::AddKeyAction { + public_key: public_key("aa"), + access_key: Some(codec::AccessKey { + nonce: 1, + permission: Some(codec::AccessKeyPermission { + permission: Some( + codec::access_key_permission::Permission::FunctionCall( + codec::FunctionCallPermission { + // allowance can be None, so let's test this out here + allowance: None, + receiver_id: "receiver".to_string(), + method_names: vec!["sayGm".to_string()], + }, + ), + ), + }), + }), + })), + }, + codec::Action { + action: Some(codec::action::Action::AddKey(codec::AddKeyAction { + public_key: public_key("aa"), + access_key: Some(codec::AccessKey { + nonce: 1, + permission: Some(codec::AccessKeyPermission { + permission: Some( + codec::access_key_permission::Permission::FullAccess( + codec::FullAccessPermission {}, + ), + ), + }), + }), + })), + }, + codec::Action { + action: Some(codec::action::Action::DeleteKey(codec::DeleteKeyAction { + public_key: public_key("aa"), + })), + }, + codec::Action { + action: Some(codec::action::Action::DeleteAccount( + codec::DeleteAccountAction { + beneficiary_id: "suicided.near".to_string(), + }, + )), + }, + ], + })), + }) + } + + fn chunk_header() -> Option { + Some(codec::ChunkHeader { + chunk_hash: vec![0x00], + prev_block_hash: vec![0x01], + outcome_root: vec![0x02], + prev_state_root: vec![0x03], + encoded_merkle_root: vec![0x04], + encoded_length: 1, + height_created: 2, + height_included: 3, + shard_id: 4, + gas_used: 5, + gas_limit: 6, + validator_reward: big_int(7), + balance_burnt: big_int(7), + outgoing_receipts_root: vec![0x07], + tx_root: vec![0x08], + validator_proposals: vec![codec::ValidatorStake { + account_id: "account".to_string(), + public_key: public_key("aa"), + stake: big_int(10), + }], + signature: signature("ff"), + }) + } + + fn execution_outcome_with_id() -> Option { + Some(codec::ExecutionOutcomeWithId { + proof: Some(codec::MerklePath { path: vec![] }), + block_hash: hash("aa"), + id: hash("beef"), + outcome: execution_outcome(), + }) + } + + fn execution_outcome() -> Option { + Some(codec::ExecutionOutcome { + logs: vec!["string".to_string()], + receipt_ids: vec![], + gas_burnt: 1, + tokens_burnt: big_int(2), + executor_id: "near".to_string(), + metadata: 0, + status: Some(codec::execution_outcome::Status::SuccessValue( + codec::SuccessValueExecutionStatus { value: vec![0x00] }, + )), + }) + } + + fn big_int(input: u64) -> Option { + let value = + BigInt::try_from(input).expect(format!("Invalid BigInt value {}", input).as_ref()); + let bytes = value.to_signed_bytes_le(); + + Some(codec::BigInt { bytes }) + } + + fn hash(input: &str) -> Option { + Some(codec::CryptoHash { + bytes: hex::decode(input).expect(format!("Invalid hash value {}", input).as_ref()), + }) + } + + fn public_key(input: &str) -> Option { + Some(codec::PublicKey { + r#type: 0, + bytes: hex::decode(input).expect(format!("Invalid PublicKey value {}", input).as_ref()), + }) + } + + fn signature(input: &str) -> Option { + Some(codec::Signature { + r#type: 0, + bytes: hex::decode(input).expect(format!("Invalid Signature value {}", input).as_ref()), + }) + } + + struct BytesHeap { + api_version: graph::semver::Version, + memory: Vec, + } + + impl BytesHeap { + fn new(api_version: graph::semver::Version) -> Self { + Self { + api_version, + memory: vec![], + } + } + } + + impl AscHeap for BytesHeap { + fn raw_new( + &mut self, + bytes: &[u8], + _gas: &GasCounter, + ) -> Result { + self.memory.extend_from_slice(bytes); + Ok((self.memory.len() - bytes.len()) as u32) + } + + fn get( + &self, + offset: u32, + size: u32, + _gas: &GasCounter, + ) -> Result, DeterministicHostError> { + let memory_byte_count = self.memory.len(); + if memory_byte_count == 0 { + return Err(DeterministicHostError::from(anyhow!( + "No memory is allocated" + ))); + } + + let start_offset = offset as usize; + let end_offset_exclusive = start_offset + size as usize; + + if start_offset >= memory_byte_count { + return Err(DeterministicHostError::from(anyhow!( + "Start offset {} is outside of allocated memory, max offset is {}", + start_offset, + memory_byte_count - 1 + ))); + } + + if end_offset_exclusive > memory_byte_count { + return Err(DeterministicHostError::from(anyhow!( + "End of offset {} is outside of allocated memory, max offset is {}", + end_offset_exclusive, + memory_byte_count - 1 + ))); + } + + return Ok(Vec::from(&self.memory[start_offset..end_offset_exclusive])); + } + + fn api_version(&self) -> graph::semver::Version { + self.api_version.clone() + } + + fn asc_type_id( + &mut self, + type_id_index: graph::runtime::IndexForAscTypeId, + ) -> Result { + // Not totally clear what is the purpose of this method, why not a default implementation here? + Ok(type_id_index as u32) + } + } +} diff --git a/node/Cargo.toml b/node/Cargo.toml index 5f57222aee1..cbfc9704671 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -23,6 +23,7 @@ url = "2.2.1" crossbeam-channel = "0.5.4" graph = { path = "../graph" } graph-core = { path = "../core" } +graph-chain-arweave = { path = "../chain/arweave" } graph-chain-ethereum = { path = "../chain/ethereum" } graph-chain-near = { path = "../chain/near" } graph-chain-tendermint = { path = "../chain/tendermint" } From a7fa3fb1bf45d58e735f63515dfd97f0d240e7be Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Mon, 11 Apr 2022 14:29:57 +0800 Subject: [PATCH 02/19] feat(chain): add arweave runtime abi --- chain/arweave/Cargo.toml | 1 - chain/arweave/build.rs | 4 +- chain/arweave/proto/codec.proto | 521 ----------- chain/arweave/proto/type.proto | 107 +++ chain/arweave/src/protobuf/google.protobuf.rs | 1 + .../src/protobuf/sf.arweave.r#type.v1.rs | 140 +++ .../arweave/src/protobuf/sf.near.codec.v1.rs | 848 ------------------ chain/arweave/src/runtime/abi.rs | 658 ++------------ chain/arweave/src/runtime/generated.rs | 641 ++----------- graph/src/blockchain/mod.rs | 4 + graph/src/runtime/mod.rs | 17 +- 11 files changed, 396 insertions(+), 2546 deletions(-) delete mode 100644 chain/arweave/proto/codec.proto create mode 100644 chain/arweave/proto/type.proto create mode 100644 chain/arweave/src/protobuf/google.protobuf.rs create mode 100644 chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs delete mode 100644 chain/arweave/src/protobuf/sf.near.codec.v1.rs diff --git a/chain/arweave/Cargo.toml b/chain/arweave/Cargo.toml index e4170d0670b..62c1d18eb93 100644 --- a/chain/arweave/Cargo.toml +++ b/chain/arweave/Cargo.toml @@ -22,4 +22,3 @@ graph-core = { path = "../../core" } graph-store-postgres = { path = "../../store/postgres" } pretty_assertions = "0.7.2" test-store = { path = "../../store/test-store" } - diff --git a/chain/arweave/build.rs b/chain/arweave/build.rs index 435a5a3faa2..4a515f5c90e 100644 --- a/chain/arweave/build.rs +++ b/chain/arweave/build.rs @@ -3,6 +3,6 @@ fn main() { tonic_build::configure() .out_dir("src/protobuf") .format(true) - .compile(&["proto/codec.proto"], &["proto"]) - .expect("Failed to compile Firehose NEAR proto(s)"); + .compile(&["proto/type.proto"], &["proto"]) + .expect("Failed to compile Firehose Arweave proto(s)"); } diff --git a/chain/arweave/proto/codec.proto b/chain/arweave/proto/codec.proto deleted file mode 100644 index 22a0267669a..00000000000 --- a/chain/arweave/proto/codec.proto +++ /dev/null @@ -1,521 +0,0 @@ -syntax = "proto3"; - -package sf.near.codec.v1; - -option go_package = "github.com/streamingfast/sf-near/pb/sf/near/codec/v1;pbcodec"; - -message Block { - string author = 1; - BlockHeader header = 2; - repeated ChunkHeader chunk_headers = 3; - repeated IndexerShard shards = 4; - repeated StateChangeWithCause state_changes = 5; -} - -// HeaderOnlyBlock is a standard [Block] structure where all other fields are -// removed so that hydrating that object from a [Block] bytes payload will -// drastically reduced allocated memory required to hold the full block. -// -// This can be used to unpack a [Block] when only the [BlockHeader] information -// is required and greatly reduced required memory. -message HeaderOnlyBlock { - BlockHeader header = 2; -} - -message StateChangeWithCause { - StateChangeValue value = 1; - StateChangeCause cause = 2; -} - -message StateChangeCause { - oneof cause { - NotWritableToDisk not_writable_to_disk = 1; - InitialState initial_state = 2; - TransactionProcessing transaction_processing = 3; - ActionReceiptProcessingStarted action_receipt_processing_started = 4; - ActionReceiptGasReward action_receipt_gas_reward = 5; - ReceiptProcessing receipt_processing = 6; - PostponedReceipt postponed_receipt = 7; - UpdatedDelayedReceipts updated_delayed_receipts = 8; - ValidatorAccountsUpdate validator_accounts_update = 9; - Migration migration = 10; - } - - message NotWritableToDisk {} - message InitialState {} - message TransactionProcessing {CryptoHash tx_hash = 1;} - message ActionReceiptProcessingStarted {CryptoHash receipt_hash = 1;} - message ActionReceiptGasReward {CryptoHash tx_hash = 1;} - message ReceiptProcessing {CryptoHash tx_hash = 1;} - message PostponedReceipt {CryptoHash tx_hash = 1;} - message UpdatedDelayedReceipts {} - message ValidatorAccountsUpdate {} - message Migration {} -} - -message StateChangeValue { - oneof value { - AccountUpdate account_update = 1; - AccountDeletion account_deletion = 2; - AccessKeyUpdate access_key_update = 3; - AccessKeyDeletion access_key_deletion = 4; - DataUpdate data_update = 5; - DataDeletion data_deletion = 6; - ContractCodeUpdate contract_code_update = 7; - ContractCodeDeletion contract_deletion = 8; - } - - message AccountUpdate {string account_id = 1; Account account = 2;} - message AccountDeletion {string account_id = 1;} - message AccessKeyUpdate { - string account_id = 1; - PublicKey public_key = 2; - AccessKey access_key = 3; - } - message AccessKeyDeletion { - string account_id = 1; - PublicKey public_key = 2; - } - message DataUpdate { - string account_id = 1; - bytes key = 2; - bytes value = 3; - } - message DataDeletion { - string account_id = 1; - bytes key = 2; - } - message ContractCodeUpdate { - string account_id = 1; - bytes code = 2; - } - message ContractCodeDeletion { - string account_id = 1; - } -} - -message Account { - BigInt amount = 1; - BigInt locked = 2; - CryptoHash code_hash = 3; - uint64 storage_usage = 4; -} - -message BlockHeader { - uint64 height = 1; - uint64 prev_height = 2; - CryptoHash epoch_id = 3; - CryptoHash next_epoch_id = 4; - CryptoHash hash = 5; - CryptoHash prev_hash = 6; - CryptoHash prev_state_root = 7; - CryptoHash chunk_receipts_root = 8; - CryptoHash chunk_headers_root = 9; - CryptoHash chunk_tx_root = 10; - CryptoHash outcome_root = 11; - uint64 chunks_included = 12; - CryptoHash challenges_root = 13; - uint64 timestamp = 14; - uint64 timestamp_nanosec = 15; - CryptoHash random_value = 16; - repeated ValidatorStake validator_proposals = 17; - repeated bool chunk_mask = 18; - BigInt gas_price = 19; - uint64 block_ordinal = 20; - BigInt total_supply = 21; - repeated SlashedValidator challenges_result = 22; - uint64 last_final_block_height = 23; - CryptoHash last_final_block = 24; - uint64 last_ds_final_block_height = 25; - CryptoHash last_ds_final_block = 26; - CryptoHash next_bp_hash = 27; - CryptoHash block_merkle_root = 28; - bytes epoch_sync_data_hash = 29; - repeated Signature approvals = 30; - Signature signature = 31; - uint32 latest_protocol_version = 32; -} - -message BigInt { - bytes bytes = 1; -} -message CryptoHash { - bytes bytes = 1; -} - -enum CurveKind { - ED25519 = 0; - SECP256K1 = 1; -} - -message Signature { - CurveKind type = 1; - bytes bytes = 2; -} - -message PublicKey { - CurveKind type = 1; - bytes bytes = 2; -} - -message ValidatorStake { - string account_id = 1; - PublicKey public_key = 2; - BigInt stake = 3; -} - -message SlashedValidator { - string account_id = 1; - bool is_double_sign = 2; -} - -message ChunkHeader { - bytes chunk_hash = 1; - bytes prev_block_hash = 2; - bytes outcome_root = 3; - bytes prev_state_root = 4; - bytes encoded_merkle_root = 5; - uint64 encoded_length = 6; - uint64 height_created = 7; - uint64 height_included = 8; - uint64 shard_id = 9; - uint64 gas_used = 10; - uint64 gas_limit = 11; - BigInt validator_reward = 12; - BigInt balance_burnt = 13; - bytes outgoing_receipts_root = 14; - bytes tx_root = 15; - repeated ValidatorStake validator_proposals = 16; - Signature signature = 17; -} - -message IndexerShard { - uint64 shard_id = 1; - IndexerChunk chunk = 2; - repeated IndexerExecutionOutcomeWithReceipt receipt_execution_outcomes = 3; -} - -message IndexerExecutionOutcomeWithReceipt { - ExecutionOutcomeWithId execution_outcome = 1; - Receipt receipt = 2; -} - -message IndexerChunk { - string author = 1; - ChunkHeader header = 2; - repeated IndexerTransactionWithOutcome transactions = 3; - repeated Receipt receipts = 4; -} - -message IndexerTransactionWithOutcome { - SignedTransaction transaction = 1; - IndexerExecutionOutcomeWithOptionalReceipt outcome = 2; -} - -message SignedTransaction { - string signer_id = 1; - PublicKey public_key = 2; - uint64 nonce = 3; - string receiver_id = 4; - repeated Action actions = 5; - Signature signature = 6; - CryptoHash hash = 7; -} - -message IndexerExecutionOutcomeWithOptionalReceipt { - ExecutionOutcomeWithId execution_outcome = 1; - Receipt receipt = 2; -} - -message Receipt { - string predecessor_id = 1; - string receiver_id = 2; - CryptoHash receipt_id = 3; - - oneof receipt { - ReceiptAction action = 10; - ReceiptData data = 11; - } -} - -message ReceiptData { - CryptoHash data_id = 1; - bytes data = 2; -} - -message ReceiptAction { - string signer_id = 1; - PublicKey signer_public_key = 2; - BigInt gas_price = 3; - repeated DataReceiver output_data_receivers = 4; - repeated CryptoHash input_data_ids = 5; - repeated Action actions = 6; -} - -message DataReceiver { - CryptoHash data_id = 1; - string receiver_id = 2; -} - -message ExecutionOutcomeWithId { - MerklePath proof = 1; - CryptoHash block_hash = 2; - CryptoHash id = 3; - ExecutionOutcome outcome = 4; -} - -message ExecutionOutcome { - repeated string logs = 1; - repeated CryptoHash receipt_ids = 2; - uint64 gas_burnt = 3; - BigInt tokens_burnt = 4; - string executor_id = 5; - oneof status { - UnknownExecutionStatus unknown = 20; - FailureExecutionStatus failure = 21; - SuccessValueExecutionStatus success_value = 22; - SuccessReceiptIdExecutionStatus success_receipt_id = 23; - } - ExecutionMetadata metadata = 6; -} - -enum ExecutionMetadata { - ExecutionMetadataV1 = 0; -} - -message SuccessValueExecutionStatus { - bytes value = 1; -} - -message SuccessReceiptIdExecutionStatus { - CryptoHash id = 1; -} - -message UnknownExecutionStatus {} -message FailureExecutionStatus { - oneof failure { - ActionError action_error = 1; - InvalidTxError invalid_tx_error = 2; - } -} - -message ActionError { - uint64 index = 1; - oneof kind { - AccountAlreadyExistsErrorKind account_already_exist = 21; - AccountDoesNotExistErrorKind account_does_not_exist = 22; - CreateAccountOnlyByRegistrarErrorKind create_account_only_by_registrar = 23; - CreateAccountNotAllowedErrorKind create_account_not_allowed = 24; - ActorNoPermissionErrorKind actor_no_permission =25; - DeleteKeyDoesNotExistErrorKind delete_key_does_not_exist = 26; - AddKeyAlreadyExistsErrorKind add_key_already_exists = 27; - DeleteAccountStakingErrorKind delete_account_staking = 28; - LackBalanceForStateErrorKind lack_balance_for_state = 29; - TriesToUnstakeErrorKind tries_to_unstake = 30; - TriesToStakeErrorKind tries_to_stake = 31; - InsufficientStakeErrorKind insufficient_stake = 32; - FunctionCallErrorKind function_call = 33; - NewReceiptValidationErrorKind new_receipt_validation = 34; - OnlyImplicitAccountCreationAllowedErrorKind only_implicit_account_creation_allowed = 35; - DeleteAccountWithLargeStateErrorKind delete_account_with_large_state = 36; - } -} - -message AccountAlreadyExistsErrorKind { - string account_id = 1; -} - -message AccountDoesNotExistErrorKind { - string account_id = 1; -} - -/// A top-level account ID can only be created by registrar. -message CreateAccountOnlyByRegistrarErrorKind{ - string account_id = 1; - string registrar_account_id = 2; - string predecessor_id = 3; -} - -message CreateAccountNotAllowedErrorKind{ - string account_id = 1; - string predecessor_id = 2; -} - -message ActorNoPermissionErrorKind{ - string account_id = 1; - string actor_id = 2; -} - -message DeleteKeyDoesNotExistErrorKind{ - string account_id = 1; - PublicKey public_key = 2; -} - -message AddKeyAlreadyExistsErrorKind{ - string account_id = 1; - PublicKey public_key = 2; -} - -message DeleteAccountStakingErrorKind{ - string account_id = 1; -} - -message LackBalanceForStateErrorKind{ - string account_id = 1; - BigInt balance = 2; -} - -message TriesToUnstakeErrorKind{ - string account_id = 1; -} - -message TriesToStakeErrorKind{ - string account_id = 1; - BigInt stake = 2; - BigInt locked = 3; - BigInt balance = 4; -} - -message InsufficientStakeErrorKind{ - string account_id = 1; - BigInt stake = 2; - BigInt minimum_stake = 3; -} - -message FunctionCallErrorKind { - FunctionCallErrorSer error = 1; -} - -enum FunctionCallErrorSer { //todo: add more detail? - CompilationError = 0; - LinkError = 1; - MethodResolveError = 2; - WasmTrap = 3; - WasmUnknownError = 4; - HostError = 5; - _EVMError = 6; - ExecutionError = 7; -} - -message NewReceiptValidationErrorKind { - ReceiptValidationError error = 1; -} - -enum ReceiptValidationError { //todo: add more detail? - InvalidPredecessorId = 0; - InvalidReceiverAccountId = 1; - InvalidSignerAccountId = 2; - InvalidDataReceiverId = 3; - ReturnedValueLengthExceeded = 4; - NumberInputDataDependenciesExceeded = 5; - ActionsValidationError = 6; -} - -message OnlyImplicitAccountCreationAllowedErrorKind{ - string account_id = 1; -} - -message DeleteAccountWithLargeStateErrorKind{ - string account_id = 1; -} - -enum InvalidTxError { //todo: add more detail? - InvalidAccessKeyError = 0; - InvalidSignerId = 1; - SignerDoesNotExist = 2; - InvalidNonce = 3; - NonceTooLarge = 4; - InvalidReceiverId = 5; - InvalidSignature = 6; - NotEnoughBalance = 7; - LackBalanceForState = 8; - CostOverflow = 9; - InvalidChain = 10; - Expired = 11; - ActionsValidation = 12; - TransactionSizeExceeded = 13; -} - -message MerklePath { - repeated MerklePathItem path = 1; -} - -message MerklePathItem { - CryptoHash hash = 1; - Direction direction = 2; -} - -enum Direction { - left = 0; - right = 1; -} - -message Action { - oneof action { - CreateAccountAction create_account = 1; - DeployContractAction deploy_contract = 2; - FunctionCallAction function_call = 3; - TransferAction transfer = 4; - StakeAction stake = 5; - AddKeyAction add_key = 6; - DeleteKeyAction delete_key = 7; - DeleteAccountAction delete_account = 8; - } -} - -message CreateAccountAction { -} - -message DeployContractAction { - bytes code = 1; -} - -message FunctionCallAction { - string method_name = 1; - bytes args = 2; - uint64 gas = 3; - BigInt deposit = 4; -} - -message TransferAction { - BigInt deposit = 1; -} - -message StakeAction { - BigInt stake = 1; - PublicKey public_key = 2; -} - -message AddKeyAction { - PublicKey public_key = 1; - AccessKey access_key = 2; -} - -message DeleteKeyAction { - PublicKey public_key = 1; -} - -message DeleteAccountAction { - string beneficiary_id = 1; -} - -message AccessKey { - uint64 nonce = 1; - AccessKeyPermission permission = 2; -} - -message AccessKeyPermission { - oneof permission { - FunctionCallPermission function_call = 1; - FullAccessPermission full_access = 2; - } -} - -message FunctionCallPermission { - BigInt allowance = 1; - string receiver_id = 2; - repeated string method_names = 3; -} - -message FullAccessPermission { -} diff --git a/chain/arweave/proto/type.proto b/chain/arweave/proto/type.proto new file mode 100644 index 00000000000..c15d1c1562e --- /dev/null +++ b/chain/arweave/proto/type.proto @@ -0,0 +1,107 @@ +syntax = "proto3"; + +package sf.arweave.type.v1; + +option go_package = "github.com/ChainSafe/firehose-arweave/pb/sf/arweave/type/v1;pbcodec"; + +message Block { + // Firehose block version (unrelated to Arweave block version) + uint32 ver = 1; + // The block identifier + bytes indep_hash = 2; + // The nonce chosen to solve the mining problem + bytes nonce = 3; + // `indep_hash` of the previous block in the weave + bytes previous_block = 4; + // POSIX time of block discovery + uint64 timestamp = 5; + // POSIX time of the last difficulty retarget + uint64 last_retarget = 6; + // Mining difficulty; the number `hash` must be greater than. + string diff = 7; + // How many blocks have passed since the genesis block + uint64 height = 8; + // Mining solution hash of the block; must satisfy the mining difficulty + bytes hash = 9; + // Merkle root of the tree of Merkle roots of block's transactions' data. + optional bytes tx_root = 10; + // Transactions contained within this block + repeated Transaction txs = 11; + // The root hash of the Merkle Patricia Tree containing + // all wallet (account) balances and the identifiers + // of the last transactions posted by them; if any. + bytes wallet_list = 12; + // (string or) Address of the account to receive the block rewards. Can also be unclaimed which is encoded as a null byte + bytes reward_addr = 13; + // Tags that a block producer can add to a block + repeated Tag tags = 14; + // Size of reward pool + string reward_pool = 15; + // Size of the weave in bytes + string weave_size = 16; + // Size of this block in bytes + string block_size = 17; + // Required after the version 1.8 fork. Zero otherwise. + // The sum of the average number of hashes computed + // by the network to produce the past blocks including this one. + optional string cumulative_diff = 18; + // The list of the block identifiers of the last + // STORE_BLOCKS_BEHIND_CURRENT blocks. + repeated bytes hash_list = 19; + // Required after the version 1.8 fork. Null byte otherwise. + // The Merkle root of the block index - the list of {`indep_hash`; `weave_size`; `tx_root`} triplets + optional bytes hash_list_merkle = 20; + // The proof of access; Used after v2.4 only; set as defaults otherwise + ProofOfAccess poa = 21; +} + +// A succinct proof of access to a recall byte found in a TX +message ProofOfAccess { + // The recall byte option chosen; global offset of index byte + string option = 1; + // The path through the Merkle tree of transactions' `data_root`s; + // from the `data_root` being proven to the corresponding `tx_root` + bytes tx_path = 2; + // The path through the Merkle tree of identifiers of chunks of the + // corresponding transaction; from the chunk being proven to the + // corresponding `data_root`. + bytes data_path = 3; + // The data chunk. + bytes chunk = 4; +} + +message Transaction { + // 1 or 2 for v1 or v2 transactions. More allowable in the future + uint32 format = 1; + // The transaction identifier. + string id = 2; + // Either the identifier of the previous transaction from the same + // wallet or the identifier of one of the last ?MAX_TX_ANCHOR_DEPTH blocks. + bytes last_tx = 3; + // The public key the transaction is signed with. + bytes owner = 4; + // A list of arbitrary key-value pairs + repeated Tag tags = 5; + // The address of the recipient; if any. The SHA2-256 hash of the public key. + bytes target = 6; + // The amount of Winstons to send to the recipient; if any. + string quantity = 7; + // The data to upload; if any. For v2 transactions; the field is optional + // - a fee is charged based on the `data_size` field; + // data may be uploaded any time later in chunks. + bytes data = 8; + // Size in bytes of the transaction data. + string data_size = 9; + // The Merkle root of the Merkle tree of data chunks. + bytes data_root = 10; + // The signature. + bytes signature = 11; + // The fee in Winstons. + string reward = 12; +} + + +message Tag { + bytes name = 1; + bytes value = 2; +} diff --git a/chain/arweave/src/protobuf/google.protobuf.rs b/chain/arweave/src/protobuf/google.protobuf.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/chain/arweave/src/protobuf/google.protobuf.rs @@ -0,0 +1 @@ + diff --git a/chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs b/chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs new file mode 100644 index 00000000000..6ca30a2e9ed --- /dev/null +++ b/chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs @@ -0,0 +1,140 @@ +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Block { + /// Firehose block version (unrelated to Arweave block version) + #[prost(uint32, tag = "1")] + pub ver: u32, + /// The block identifier + #[prost(bytes = "vec", tag = "2")] + pub indep_hash: ::prost::alloc::vec::Vec, + /// The nonce chosen to solve the mining problem + #[prost(bytes = "vec", tag = "3")] + pub nonce: ::prost::alloc::vec::Vec, + /// `indep_hash` of the previous block in the weave + #[prost(bytes = "vec", tag = "4")] + pub previous_block: ::prost::alloc::vec::Vec, + /// POSIX time of block discovery + #[prost(uint64, tag = "5")] + pub timestamp: u64, + /// POSIX time of the last difficulty retarget + #[prost(uint64, tag = "6")] + pub last_retarget: u64, + /// Mining difficulty; the number `hash` must be greater than. + #[prost(string, tag = "7")] + pub diff: ::prost::alloc::string::String, + /// How many blocks have passed since the genesis block + #[prost(uint64, tag = "8")] + pub height: u64, + /// Mining solution hash of the block; must satisfy the mining difficulty + #[prost(bytes = "vec", tag = "9")] + pub hash: ::prost::alloc::vec::Vec, + /// Merkle root of the tree of Merkle roots of block's transactions' data. + #[prost(bytes = "vec", optional, tag = "10")] + pub tx_root: ::core::option::Option<::prost::alloc::vec::Vec>, + /// Transactions contained within this block + #[prost(message, repeated, tag = "11")] + pub txs: ::prost::alloc::vec::Vec, + /// The root hash of the Merkle Patricia Tree containing + /// all wallet (account) balances and the identifiers + /// of the last transactions posted by them; if any. + #[prost(bytes = "vec", tag = "12")] + pub wallet_list: ::prost::alloc::vec::Vec, + /// (string or) Address of the account to receive the block rewards. Can also be unclaimed which is encoded as a null byte + #[prost(bytes = "vec", tag = "13")] + pub reward_addr: ::prost::alloc::vec::Vec, + /// Tags that a block producer can add to a block + #[prost(message, repeated, tag = "14")] + pub tags: ::prost::alloc::vec::Vec, + /// Size of reward pool + #[prost(string, tag = "15")] + pub reward_pool: ::prost::alloc::string::String, + /// Size of the weave in bytes + #[prost(string, tag = "16")] + pub weave_size: ::prost::alloc::string::String, + /// Size of this block in bytes + #[prost(string, tag = "17")] + pub block_size: ::prost::alloc::string::String, + /// Required after the version 1.8 fork. Zero otherwise. + /// The sum of the average number of hashes computed + /// by the network to produce the past blocks including this one. + #[prost(string, optional, tag = "18")] + pub cumulative_diff: ::core::option::Option<::prost::alloc::string::String>, + /// The list of the block identifiers of the last + /// STORE_BLOCKS_BEHIND_CURRENT blocks. + #[prost(bytes = "vec", repeated, tag = "19")] + pub hash_list: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + /// Required after the version 1.8 fork. Null byte otherwise. + /// The Merkle root of the block index - the list of {`indep_hash`; `weave_size`; `tx_root`} triplets + #[prost(bytes = "vec", optional, tag = "20")] + pub hash_list_merkle: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The proof of access; Used after v2.4 only; set as defaults otherwise + #[prost(message, optional, tag = "21")] + pub poa: ::core::option::Option, +} +/// A succinct proof of access to a recall byte found in a TX +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProofOfAccess { + /// The recall byte option chosen; global offset of index byte + #[prost(string, tag = "1")] + pub option: ::prost::alloc::string::String, + /// The path through the Merkle tree of transactions' `data_root`s; + /// from the `data_root` being proven to the corresponding `tx_root` + #[prost(bytes = "vec", tag = "2")] + pub tx_path: ::prost::alloc::vec::Vec, + /// The path through the Merkle tree of identifiers of chunks of the + /// corresponding transaction; from the chunk being proven to the + /// corresponding `data_root`. + #[prost(bytes = "vec", tag = "3")] + pub data_path: ::prost::alloc::vec::Vec, + /// The data chunk. + #[prost(bytes = "vec", tag = "4")] + pub chunk: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Transaction { + /// 1 or 2 for v1 or v2 transactions. More allowable in the future + #[prost(uint32, tag = "1")] + pub format: u32, + /// The transaction identifier. + #[prost(string, tag = "2")] + pub id: ::prost::alloc::string::String, + /// Either the identifier of the previous transaction from the same + /// wallet or the identifier of one of the last ?MAX_TX_ANCHOR_DEPTH blocks. + #[prost(bytes = "vec", tag = "3")] + pub last_tx: ::prost::alloc::vec::Vec, + /// The public key the transaction is signed with. + #[prost(bytes = "vec", tag = "4")] + pub owner: ::prost::alloc::vec::Vec, + /// A list of arbitrary key-value pairs + #[prost(message, repeated, tag = "5")] + pub tags: ::prost::alloc::vec::Vec, + /// The address of the recipient; if any. The SHA2-256 hash of the public key. + #[prost(bytes = "vec", tag = "6")] + pub target: ::prost::alloc::vec::Vec, + /// The amount of Winstons to send to the recipient; if any. + #[prost(string, tag = "7")] + pub quantity: ::prost::alloc::string::String, + /// The data to upload; if any. For v2 transactions; the field is optional + /// - a fee is charged based on the `data_size` field; + /// data may be uploaded any time later in chunks. + #[prost(bytes = "vec", tag = "8")] + pub data: ::prost::alloc::vec::Vec, + /// Size in bytes of the transaction data. + #[prost(string, tag = "9")] + pub data_size: ::prost::alloc::string::String, + /// The Merkle root of the Merkle tree of data chunks. + #[prost(bytes = "vec", tag = "10")] + pub data_root: ::prost::alloc::vec::Vec, + /// The signature. + #[prost(bytes = "vec", tag = "11")] + pub signature: ::prost::alloc::vec::Vec, + /// The fee in Winstons. + #[prost(string, tag = "12")] + pub reward: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Tag { + #[prost(bytes = "vec", tag = "1")] + pub name: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "2")] + pub value: ::prost::alloc::vec::Vec, +} diff --git a/chain/arweave/src/protobuf/sf.near.codec.v1.rs b/chain/arweave/src/protobuf/sf.near.codec.v1.rs deleted file mode 100644 index e587f72e8eb..00000000000 --- a/chain/arweave/src/protobuf/sf.near.codec.v1.rs +++ /dev/null @@ -1,848 +0,0 @@ -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Block { - #[prost(string, tag = "1")] - pub author: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub header: ::core::option::Option, - #[prost(message, repeated, tag = "3")] - pub chunk_headers: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "4")] - pub shards: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "5")] - pub state_changes: ::prost::alloc::vec::Vec, -} -/// HeaderOnlyBlock is a standard [Block] structure where all other fields are -/// removed so that hydrating that object from a [Block] bytes payload will -/// drastically reduced allocated memory required to hold the full block. -/// -/// This can be used to unpack a [Block] when only the [BlockHeader] information -/// is required and greatly reduced required memory. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct HeaderOnlyBlock { - #[prost(message, optional, tag = "2")] - pub header: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StateChangeWithCause { - #[prost(message, optional, tag = "1")] - pub value: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub cause: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StateChangeCause { - #[prost( - oneof = "state_change_cause::Cause", - tags = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10" - )] - pub cause: ::core::option::Option, -} -/// Nested message and enum types in `StateChangeCause`. -pub mod state_change_cause { - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct NotWritableToDisk {} - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct InitialState {} - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct TransactionProcessing { - #[prost(message, optional, tag = "1")] - pub tx_hash: ::core::option::Option, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ActionReceiptProcessingStarted { - #[prost(message, optional, tag = "1")] - pub receipt_hash: ::core::option::Option, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ActionReceiptGasReward { - #[prost(message, optional, tag = "1")] - pub tx_hash: ::core::option::Option, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ReceiptProcessing { - #[prost(message, optional, tag = "1")] - pub tx_hash: ::core::option::Option, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct PostponedReceipt { - #[prost(message, optional, tag = "1")] - pub tx_hash: ::core::option::Option, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct UpdatedDelayedReceipts {} - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ValidatorAccountsUpdate {} - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct Migration {} - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Cause { - #[prost(message, tag = "1")] - NotWritableToDisk(NotWritableToDisk), - #[prost(message, tag = "2")] - InitialState(InitialState), - #[prost(message, tag = "3")] - TransactionProcessing(TransactionProcessing), - #[prost(message, tag = "4")] - ActionReceiptProcessingStarted(ActionReceiptProcessingStarted), - #[prost(message, tag = "5")] - ActionReceiptGasReward(ActionReceiptGasReward), - #[prost(message, tag = "6")] - ReceiptProcessing(ReceiptProcessing), - #[prost(message, tag = "7")] - PostponedReceipt(PostponedReceipt), - #[prost(message, tag = "8")] - UpdatedDelayedReceipts(UpdatedDelayedReceipts), - #[prost(message, tag = "9")] - ValidatorAccountsUpdate(ValidatorAccountsUpdate), - #[prost(message, tag = "10")] - Migration(Migration), - } -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StateChangeValue { - #[prost(oneof = "state_change_value::Value", tags = "1, 2, 3, 4, 5, 6, 7, 8")] - pub value: ::core::option::Option, -} -/// Nested message and enum types in `StateChangeValue`. -pub mod state_change_value { - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct AccountUpdate { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub account: ::core::option::Option, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct AccountDeletion { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct AccessKeyUpdate { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub public_key: ::core::option::Option, - #[prost(message, optional, tag = "3")] - pub access_key: ::core::option::Option, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct AccessKeyDeletion { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub public_key: ::core::option::Option, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct DataUpdate { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(bytes = "vec", tag = "2")] - pub key: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "3")] - pub value: ::prost::alloc::vec::Vec, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct DataDeletion { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(bytes = "vec", tag = "2")] - pub key: ::prost::alloc::vec::Vec, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ContractCodeUpdate { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(bytes = "vec", tag = "2")] - pub code: ::prost::alloc::vec::Vec, - } - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct ContractCodeDeletion { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - } - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Value { - #[prost(message, tag = "1")] - AccountUpdate(AccountUpdate), - #[prost(message, tag = "2")] - AccountDeletion(AccountDeletion), - #[prost(message, tag = "3")] - AccessKeyUpdate(AccessKeyUpdate), - #[prost(message, tag = "4")] - AccessKeyDeletion(AccessKeyDeletion), - #[prost(message, tag = "5")] - DataUpdate(DataUpdate), - #[prost(message, tag = "6")] - DataDeletion(DataDeletion), - #[prost(message, tag = "7")] - ContractCodeUpdate(ContractCodeUpdate), - #[prost(message, tag = "8")] - ContractDeletion(ContractCodeDeletion), - } -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Account { - #[prost(message, optional, tag = "1")] - pub amount: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub locked: ::core::option::Option, - #[prost(message, optional, tag = "3")] - pub code_hash: ::core::option::Option, - #[prost(uint64, tag = "4")] - pub storage_usage: u64, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockHeader { - #[prost(uint64, tag = "1")] - pub height: u64, - #[prost(uint64, tag = "2")] - pub prev_height: u64, - #[prost(message, optional, tag = "3")] - pub epoch_id: ::core::option::Option, - #[prost(message, optional, tag = "4")] - pub next_epoch_id: ::core::option::Option, - #[prost(message, optional, tag = "5")] - pub hash: ::core::option::Option, - #[prost(message, optional, tag = "6")] - pub prev_hash: ::core::option::Option, - #[prost(message, optional, tag = "7")] - pub prev_state_root: ::core::option::Option, - #[prost(message, optional, tag = "8")] - pub chunk_receipts_root: ::core::option::Option, - #[prost(message, optional, tag = "9")] - pub chunk_headers_root: ::core::option::Option, - #[prost(message, optional, tag = "10")] - pub chunk_tx_root: ::core::option::Option, - #[prost(message, optional, tag = "11")] - pub outcome_root: ::core::option::Option, - #[prost(uint64, tag = "12")] - pub chunks_included: u64, - #[prost(message, optional, tag = "13")] - pub challenges_root: ::core::option::Option, - #[prost(uint64, tag = "14")] - pub timestamp: u64, - #[prost(uint64, tag = "15")] - pub timestamp_nanosec: u64, - #[prost(message, optional, tag = "16")] - pub random_value: ::core::option::Option, - #[prost(message, repeated, tag = "17")] - pub validator_proposals: ::prost::alloc::vec::Vec, - #[prost(bool, repeated, tag = "18")] - pub chunk_mask: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "19")] - pub gas_price: ::core::option::Option, - #[prost(uint64, tag = "20")] - pub block_ordinal: u64, - #[prost(message, optional, tag = "21")] - pub total_supply: ::core::option::Option, - #[prost(message, repeated, tag = "22")] - pub challenges_result: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "23")] - pub last_final_block_height: u64, - #[prost(message, optional, tag = "24")] - pub last_final_block: ::core::option::Option, - #[prost(uint64, tag = "25")] - pub last_ds_final_block_height: u64, - #[prost(message, optional, tag = "26")] - pub last_ds_final_block: ::core::option::Option, - #[prost(message, optional, tag = "27")] - pub next_bp_hash: ::core::option::Option, - #[prost(message, optional, tag = "28")] - pub block_merkle_root: ::core::option::Option, - #[prost(bytes = "vec", tag = "29")] - pub epoch_sync_data_hash: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "30")] - pub approvals: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "31")] - pub signature: ::core::option::Option, - #[prost(uint32, tag = "32")] - pub latest_protocol_version: u32, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BigInt { - #[prost(bytes = "vec", tag = "1")] - pub bytes: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CryptoHash { - #[prost(bytes = "vec", tag = "1")] - pub bytes: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Signature { - #[prost(enumeration = "CurveKind", tag = "1")] - pub r#type: i32, - #[prost(bytes = "vec", tag = "2")] - pub bytes: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PublicKey { - #[prost(enumeration = "CurveKind", tag = "1")] - pub r#type: i32, - #[prost(bytes = "vec", tag = "2")] - pub bytes: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ValidatorStake { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub public_key: ::core::option::Option, - #[prost(message, optional, tag = "3")] - pub stake: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SlashedValidator { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(bool, tag = "2")] - pub is_double_sign: bool, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ChunkHeader { - #[prost(bytes = "vec", tag = "1")] - pub chunk_hash: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "2")] - pub prev_block_hash: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "3")] - pub outcome_root: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "4")] - pub prev_state_root: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "5")] - pub encoded_merkle_root: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "6")] - pub encoded_length: u64, - #[prost(uint64, tag = "7")] - pub height_created: u64, - #[prost(uint64, tag = "8")] - pub height_included: u64, - #[prost(uint64, tag = "9")] - pub shard_id: u64, - #[prost(uint64, tag = "10")] - pub gas_used: u64, - #[prost(uint64, tag = "11")] - pub gas_limit: u64, - #[prost(message, optional, tag = "12")] - pub validator_reward: ::core::option::Option, - #[prost(message, optional, tag = "13")] - pub balance_burnt: ::core::option::Option, - #[prost(bytes = "vec", tag = "14")] - pub outgoing_receipts_root: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "15")] - pub tx_root: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "16")] - pub validator_proposals: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "17")] - pub signature: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct IndexerShard { - #[prost(uint64, tag = "1")] - pub shard_id: u64, - #[prost(message, optional, tag = "2")] - pub chunk: ::core::option::Option, - #[prost(message, repeated, tag = "3")] - pub receipt_execution_outcomes: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct IndexerExecutionOutcomeWithReceipt { - #[prost(message, optional, tag = "1")] - pub execution_outcome: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub receipt: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct IndexerChunk { - #[prost(string, tag = "1")] - pub author: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub header: ::core::option::Option, - #[prost(message, repeated, tag = "3")] - pub transactions: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "4")] - pub receipts: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct IndexerTransactionWithOutcome { - #[prost(message, optional, tag = "1")] - pub transaction: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub outcome: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SignedTransaction { - #[prost(string, tag = "1")] - pub signer_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub public_key: ::core::option::Option, - #[prost(uint64, tag = "3")] - pub nonce: u64, - #[prost(string, tag = "4")] - pub receiver_id: ::prost::alloc::string::String, - #[prost(message, repeated, tag = "5")] - pub actions: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "6")] - pub signature: ::core::option::Option, - #[prost(message, optional, tag = "7")] - pub hash: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct IndexerExecutionOutcomeWithOptionalReceipt { - #[prost(message, optional, tag = "1")] - pub execution_outcome: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub receipt: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Receipt { - #[prost(string, tag = "1")] - pub predecessor_id: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub receiver_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "3")] - pub receipt_id: ::core::option::Option, - #[prost(oneof = "receipt::Receipt", tags = "10, 11")] - pub receipt: ::core::option::Option, -} -/// Nested message and enum types in `Receipt`. -pub mod receipt { - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Receipt { - #[prost(message, tag = "10")] - Action(super::ReceiptAction), - #[prost(message, tag = "11")] - Data(super::ReceiptData), - } -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ReceiptData { - #[prost(message, optional, tag = "1")] - pub data_id: ::core::option::Option, - #[prost(bytes = "vec", tag = "2")] - pub data: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ReceiptAction { - #[prost(string, tag = "1")] - pub signer_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub signer_public_key: ::core::option::Option, - #[prost(message, optional, tag = "3")] - pub gas_price: ::core::option::Option, - #[prost(message, repeated, tag = "4")] - pub output_data_receivers: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "5")] - pub input_data_ids: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "6")] - pub actions: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DataReceiver { - #[prost(message, optional, tag = "1")] - pub data_id: ::core::option::Option, - #[prost(string, tag = "2")] - pub receiver_id: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ExecutionOutcomeWithId { - #[prost(message, optional, tag = "1")] - pub proof: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub block_hash: ::core::option::Option, - #[prost(message, optional, tag = "3")] - pub id: ::core::option::Option, - #[prost(message, optional, tag = "4")] - pub outcome: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ExecutionOutcome { - #[prost(string, repeated, tag = "1")] - pub logs: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(message, repeated, tag = "2")] - pub receipt_ids: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "3")] - pub gas_burnt: u64, - #[prost(message, optional, tag = "4")] - pub tokens_burnt: ::core::option::Option, - #[prost(string, tag = "5")] - pub executor_id: ::prost::alloc::string::String, - #[prost(enumeration = "ExecutionMetadata", tag = "6")] - pub metadata: i32, - #[prost(oneof = "execution_outcome::Status", tags = "20, 21, 22, 23")] - pub status: ::core::option::Option, -} -/// Nested message and enum types in `ExecutionOutcome`. -pub mod execution_outcome { - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Status { - #[prost(message, tag = "20")] - Unknown(super::UnknownExecutionStatus), - #[prost(message, tag = "21")] - Failure(super::FailureExecutionStatus), - #[prost(message, tag = "22")] - SuccessValue(super::SuccessValueExecutionStatus), - #[prost(message, tag = "23")] - SuccessReceiptId(super::SuccessReceiptIdExecutionStatus), - } -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SuccessValueExecutionStatus { - #[prost(bytes = "vec", tag = "1")] - pub value: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SuccessReceiptIdExecutionStatus { - #[prost(message, optional, tag = "1")] - pub id: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct UnknownExecutionStatus {} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FailureExecutionStatus { - #[prost(oneof = "failure_execution_status::Failure", tags = "1, 2")] - pub failure: ::core::option::Option, -} -/// Nested message and enum types in `FailureExecutionStatus`. -pub mod failure_execution_status { - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Failure { - #[prost(message, tag = "1")] - ActionError(super::ActionError), - #[prost(enumeration = "super::InvalidTxError", tag = "2")] - InvalidTxError(i32), - } -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ActionError { - #[prost(uint64, tag = "1")] - pub index: u64, - #[prost( - oneof = "action_error::Kind", - tags = "21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36" - )] - pub kind: ::core::option::Option, -} -/// Nested message and enum types in `ActionError`. -pub mod action_error { - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Kind { - #[prost(message, tag = "21")] - AccountAlreadyExist(super::AccountAlreadyExistsErrorKind), - #[prost(message, tag = "22")] - AccountDoesNotExist(super::AccountDoesNotExistErrorKind), - #[prost(message, tag = "23")] - CreateAccountOnlyByRegistrar(super::CreateAccountOnlyByRegistrarErrorKind), - #[prost(message, tag = "24")] - CreateAccountNotAllowed(super::CreateAccountNotAllowedErrorKind), - #[prost(message, tag = "25")] - ActorNoPermission(super::ActorNoPermissionErrorKind), - #[prost(message, tag = "26")] - DeleteKeyDoesNotExist(super::DeleteKeyDoesNotExistErrorKind), - #[prost(message, tag = "27")] - AddKeyAlreadyExists(super::AddKeyAlreadyExistsErrorKind), - #[prost(message, tag = "28")] - DeleteAccountStaking(super::DeleteAccountStakingErrorKind), - #[prost(message, tag = "29")] - LackBalanceForState(super::LackBalanceForStateErrorKind), - #[prost(message, tag = "30")] - TriesToUnstake(super::TriesToUnstakeErrorKind), - #[prost(message, tag = "31")] - TriesToStake(super::TriesToStakeErrorKind), - #[prost(message, tag = "32")] - InsufficientStake(super::InsufficientStakeErrorKind), - #[prost(message, tag = "33")] - FunctionCall(super::FunctionCallErrorKind), - #[prost(message, tag = "34")] - NewReceiptValidation(super::NewReceiptValidationErrorKind), - #[prost(message, tag = "35")] - OnlyImplicitAccountCreationAllowed(super::OnlyImplicitAccountCreationAllowedErrorKind), - #[prost(message, tag = "36")] - DeleteAccountWithLargeState(super::DeleteAccountWithLargeStateErrorKind), - } -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AccountAlreadyExistsErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AccountDoesNotExistErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, -} -//// A top-level account ID can only be created by registrar. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CreateAccountOnlyByRegistrarErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub registrar_account_id: ::prost::alloc::string::String, - #[prost(string, tag = "3")] - pub predecessor_id: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CreateAccountNotAllowedErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub predecessor_id: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ActorNoPermissionErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub actor_id: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DeleteKeyDoesNotExistErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub public_key: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AddKeyAlreadyExistsErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub public_key: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DeleteAccountStakingErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct LackBalanceForStateErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub balance: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TriesToUnstakeErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TriesToStakeErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub stake: ::core::option::Option, - #[prost(message, optional, tag = "3")] - pub locked: ::core::option::Option, - #[prost(message, optional, tag = "4")] - pub balance: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct InsufficientStakeErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, - #[prost(message, optional, tag = "2")] - pub stake: ::core::option::Option, - #[prost(message, optional, tag = "3")] - pub minimum_stake: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FunctionCallErrorKind { - #[prost(enumeration = "FunctionCallErrorSer", tag = "1")] - pub error: i32, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct NewReceiptValidationErrorKind { - #[prost(enumeration = "ReceiptValidationError", tag = "1")] - pub error: i32, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct OnlyImplicitAccountCreationAllowedErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DeleteAccountWithLargeStateErrorKind { - #[prost(string, tag = "1")] - pub account_id: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MerklePath { - #[prost(message, repeated, tag = "1")] - pub path: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct MerklePathItem { - #[prost(message, optional, tag = "1")] - pub hash: ::core::option::Option, - #[prost(enumeration = "Direction", tag = "2")] - pub direction: i32, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Action { - #[prost(oneof = "action::Action", tags = "1, 2, 3, 4, 5, 6, 7, 8")] - pub action: ::core::option::Option, -} -/// Nested message and enum types in `Action`. -pub mod action { - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Action { - #[prost(message, tag = "1")] - CreateAccount(super::CreateAccountAction), - #[prost(message, tag = "2")] - DeployContract(super::DeployContractAction), - #[prost(message, tag = "3")] - FunctionCall(super::FunctionCallAction), - #[prost(message, tag = "4")] - Transfer(super::TransferAction), - #[prost(message, tag = "5")] - Stake(super::StakeAction), - #[prost(message, tag = "6")] - AddKey(super::AddKeyAction), - #[prost(message, tag = "7")] - DeleteKey(super::DeleteKeyAction), - #[prost(message, tag = "8")] - DeleteAccount(super::DeleteAccountAction), - } -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CreateAccountAction {} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DeployContractAction { - #[prost(bytes = "vec", tag = "1")] - pub code: ::prost::alloc::vec::Vec, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FunctionCallAction { - #[prost(string, tag = "1")] - pub method_name: ::prost::alloc::string::String, - #[prost(bytes = "vec", tag = "2")] - pub args: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "3")] - pub gas: u64, - #[prost(message, optional, tag = "4")] - pub deposit: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TransferAction { - #[prost(message, optional, tag = "1")] - pub deposit: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct StakeAction { - #[prost(message, optional, tag = "1")] - pub stake: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub public_key: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AddKeyAction { - #[prost(message, optional, tag = "1")] - pub public_key: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub access_key: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DeleteKeyAction { - #[prost(message, optional, tag = "1")] - pub public_key: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct DeleteAccountAction { - #[prost(string, tag = "1")] - pub beneficiary_id: ::prost::alloc::string::String, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AccessKey { - #[prost(uint64, tag = "1")] - pub nonce: u64, - #[prost(message, optional, tag = "2")] - pub permission: ::core::option::Option, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AccessKeyPermission { - #[prost(oneof = "access_key_permission::Permission", tags = "1, 2")] - pub permission: ::core::option::Option, -} -/// Nested message and enum types in `AccessKeyPermission`. -pub mod access_key_permission { - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Permission { - #[prost(message, tag = "1")] - FunctionCall(super::FunctionCallPermission), - #[prost(message, tag = "2")] - FullAccess(super::FullAccessPermission), - } -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FunctionCallPermission { - #[prost(message, optional, tag = "1")] - pub allowance: ::core::option::Option, - #[prost(string, tag = "2")] - pub receiver_id: ::prost::alloc::string::String, - #[prost(string, repeated, tag = "3")] - pub method_names: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FullAccessPermission {} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum CurveKind { - Ed25519 = 0, - Secp256k1 = 1, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ExecutionMetadata { - V1 = 0, -} -///todo: add more detail? -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum FunctionCallErrorSer { - CompilationError = 0, - LinkError = 1, - MethodResolveError = 2, - WasmTrap = 3, - WasmUnknownError = 4, - HostError = 5, - EvmError = 6, - ExecutionError = 7, -} -///todo: add more detail? -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ReceiptValidationError { - InvalidPredecessorId = 0, - InvalidReceiverAccountId = 1, - InvalidSignerAccountId = 2, - InvalidDataReceiverId = 3, - ReturnedValueLengthExceeded = 4, - NumberInputDataDependenciesExceeded = 5, - ActionsValidationError = 6, -} -///todo: add more detail? -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum InvalidTxError { - InvalidAccessKeyError = 0, - InvalidSignerId = 1, - SignerDoesNotExist = 2, - InvalidNonce = 3, - NonceTooLarge = 4, - InvalidReceiverId = 5, - InvalidSignature = 6, - NotEnoughBalance = 7, - LackBalanceForState = 8, - CostOverflow = 9, - InvalidChain = 10, - Expired = 11, - ActionsValidation = 12, - TransactionSizeExceeded = 13, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum Direction { - Left = 0, - Right = 1, -} diff --git a/chain/arweave/src/runtime/abi.rs b/chain/arweave/src/runtime/abi.rs index fdd3be12e6f..b8fe94c7956 100644 --- a/chain/arweave/src/runtime/abi.rs +++ b/chain/arweave/src/runtime/abi.rs @@ -7,631 +7,109 @@ use graph_runtime_wasm::asc_abi::class::{Array, AscEnum, EnumPayload, Uint8Array pub(crate) use super::generated::*; -impl ToAscObj for codec::Block { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscBlock { - author: asc_new(heap, &self.author, gas)?, - header: asc_new(heap, self.header(), gas)?, - chunks: asc_new(heap, &self.chunk_headers, gas)?, - }) - } -} - -impl ToAscObj for codec::BlockHeader { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let chunk_mask = Array::new(self.chunk_mask.as_ref(), heap, gas)?; - - Ok(AscBlockHeader { - height: self.height, - prev_height: self.prev_height, - epoch_id: asc_new(heap, self.epoch_id.as_ref().unwrap(), gas)?, - next_epoch_id: asc_new(heap, self.next_epoch_id.as_ref().unwrap(), gas)?, - hash: asc_new(heap, self.hash.as_ref().unwrap(), gas)?, - prev_hash: asc_new(heap, self.prev_hash.as_ref().unwrap(), gas)?, - prev_state_root: asc_new(heap, self.prev_state_root.as_ref().unwrap(), gas)?, - chunk_receipts_root: asc_new(heap, self.chunk_receipts_root.as_ref().unwrap(), gas)?, - chunk_headers_root: asc_new(heap, self.chunk_headers_root.as_ref().unwrap(), gas)?, - chunk_tx_root: asc_new(heap, self.chunk_tx_root.as_ref().unwrap(), gas)?, - outcome_root: asc_new(heap, self.outcome_root.as_ref().unwrap(), gas)?, - chunks_included: self.chunks_included, - challenges_root: asc_new(heap, self.challenges_root.as_ref().unwrap(), gas)?, - timestamp_nanosec: self.timestamp_nanosec, - random_value: asc_new(heap, self.random_value.as_ref().unwrap(), gas)?, - validator_proposals: asc_new(heap, &self.validator_proposals, gas)?, - chunk_mask: AscPtr::alloc_obj(chunk_mask, heap, gas)?, - gas_price: asc_new(heap, self.gas_price.as_ref().unwrap(), gas)?, - block_ordinal: self.block_ordinal, - total_supply: asc_new(heap, self.total_supply.as_ref().unwrap(), gas)?, - challenges_result: asc_new(heap, &self.challenges_result, gas)?, - last_final_block: asc_new(heap, self.last_final_block.as_ref().unwrap(), gas)?, - last_ds_final_block: asc_new(heap, self.last_ds_final_block.as_ref().unwrap(), gas)?, - next_bp_hash: asc_new(heap, self.next_bp_hash.as_ref().unwrap(), gas)?, - block_merkle_root: asc_new(heap, self.block_merkle_root.as_ref().unwrap(), gas)?, - epoch_sync_data_hash: asc_new(heap, self.epoch_sync_data_hash.as_slice(), gas)?, - approvals: asc_new(heap, &self.approvals, gas)?, - signature: asc_new(heap, &self.signature.as_ref().unwrap(), gas)?, - latest_protocol_version: self.latest_protocol_version, - }) - } -} - -impl ToAscObj for codec::ChunkHeader { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscChunkHeader { - chunk_hash: asc_new(heap, self.chunk_hash.as_slice(), gas)?, - signature: asc_new(heap, &self.signature.as_ref().unwrap(), gas)?, - prev_block_hash: asc_new(heap, self.prev_block_hash.as_slice(), gas)?, - prev_state_root: asc_new(heap, self.prev_state_root.as_slice(), gas)?, - encoded_merkle_root: asc_new(heap, self.encoded_merkle_root.as_slice(), gas)?, - encoded_length: self.encoded_length, - height_created: self.height_created, - height_included: self.height_included, - shard_id: self.shard_id, - gas_used: self.gas_used, - gas_limit: self.gas_limit, - balance_burnt: asc_new(heap, self.balance_burnt.as_ref().unwrap(), gas)?, - outgoing_receipts_root: asc_new(heap, self.outgoing_receipts_root.as_slice(), gas)?, - tx_root: asc_new(heap, self.tx_root.as_slice(), gas)?, - validator_proposals: asc_new(heap, &self.validator_proposals, gas)?, - - _padding: 0, - }) - } -} - -impl ToAscObj for Vec { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); - let content = content?; - Ok(AscChunkHeaderArray(Array::new(&*content, heap, gas)?)) - } -} - -impl ToAscObj for ReceiptWithOutcome { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscReceiptWithOutcome { - outcome: asc_new(heap, &self.outcome, gas)?, - receipt: asc_new(heap, &self.receipt, gas)?, - block: asc_new(heap, self.block.as_ref(), gas)?, - }) - } -} - -impl ToAscObj for codec::Receipt { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let action = match self.receipt.as_ref().unwrap() { - codec::receipt::Receipt::Action(action) => action, - codec::receipt::Receipt::Data(_) => { - return Err(DeterministicHostError::from(anyhow!( - "Data receipt are now allowed" - ))); - } - }; - - Ok(AscActionReceipt { - id: asc_new(heap, &self.receipt_id.as_ref().unwrap(), gas)?, - predecessor_id: asc_new(heap, &self.predecessor_id, gas)?, - receiver_id: asc_new(heap, &self.receiver_id, gas)?, - signer_id: asc_new(heap, &action.signer_id, gas)?, - signer_public_key: asc_new(heap, action.signer_public_key.as_ref().unwrap(), gas)?, - gas_price: asc_new(heap, action.gas_price.as_ref().unwrap(), gas)?, - output_data_receivers: asc_new(heap, &action.output_data_receivers, gas)?, - input_data_ids: asc_new(heap, &action.input_data_ids, gas)?, - actions: asc_new(heap, &action.actions, gas)?, - }) - } -} - -impl ToAscObj for codec::Action { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let (kind, payload) = match self.action.as_ref().unwrap() { - codec::action::Action::CreateAccount(action) => ( - AscActionKind::CreateAccount, - asc_new(heap, action, gas)?.to_payload(), - ), - codec::action::Action::DeployContract(action) => ( - AscActionKind::DeployContract, - asc_new(heap, action, gas)?.to_payload(), - ), - codec::action::Action::FunctionCall(action) => ( - AscActionKind::FunctionCall, - asc_new(heap, action, gas)?.to_payload(), - ), - codec::action::Action::Transfer(action) => ( - AscActionKind::Transfer, - asc_new(heap, action, gas)?.to_payload(), - ), - codec::action::Action::Stake(action) => ( - AscActionKind::Stake, - asc_new(heap, action, gas)?.to_payload(), - ), - codec::action::Action::AddKey(action) => ( - AscActionKind::AddKey, - asc_new(heap, action, gas)?.to_payload(), - ), - codec::action::Action::DeleteKey(action) => ( - AscActionKind::DeleteKey, - asc_new(heap, action, gas)?.to_payload(), - ), - codec::action::Action::DeleteAccount(action) => ( - AscActionKind::DeleteAccount, - asc_new(heap, action, gas)?.to_payload(), - ), - }; - - Ok(AscActionEnum(AscEnum { - kind, - _padding: 0, - payload: EnumPayload(payload), - })) - } -} - -impl ToAscObj for Vec { +impl ToAscObj for codec::Tag { fn to_asc_obj( &self, heap: &mut H, gas: &GasCounter, - ) -> Result { - let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); - let content = content?; - Ok(AscActionEnumArray(Array::new(&*content, heap, gas)?)) - } -} - -impl ToAscObj for codec::CreateAccountAction { - fn to_asc_obj( - &self, - _heap: &mut H, - _gas: &GasCounter, - ) -> Result { - Ok(AscCreateAccountAction {}) - } -} - -impl ToAscObj for codec::DeployContractAction { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscDeployContractAction { - code: asc_new(heap, self.code.as_slice(), gas)?, - }) - } -} - -impl ToAscObj for codec::FunctionCallAction { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscFunctionCallAction { - method_name: asc_new(heap, &self.method_name, gas)?, - args: asc_new(heap, self.args.as_slice(), gas)?, - gas: self.gas, - deposit: asc_new(heap, self.deposit.as_ref().unwrap(), gas)?, - _padding: 0, - }) - } -} - -impl ToAscObj for codec::TransferAction { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscTransferAction { - deposit: asc_new(heap, self.deposit.as_ref().unwrap(), gas)?, - }) - } -} - -impl ToAscObj for codec::StakeAction { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscStakeAction { - stake: asc_new(heap, self.stake.as_ref().unwrap(), gas)?, - public_key: asc_new(heap, self.public_key.as_ref().unwrap(), gas)?, + ) -> Result { + Ok(AscTag { + name: asc_new(heap, self.name.as_slice(), gas)?, + value: asc_new(heap, self.value.as_slice(), gas)?, }) } } -impl ToAscObj for codec::AddKeyAction { +impl ToAscObj for Vec { fn to_asc_obj( &self, heap: &mut H, gas: &GasCounter, - ) -> Result { - Ok(AscAddKeyAction { - public_key: asc_new(heap, self.public_key.as_ref().unwrap(), gas)?, - access_key: asc_new(heap, self.access_key.as_ref().unwrap(), gas)?, - }) + ) -> Result { + let content = self + .iter() + .map(|x| asc_new(heap, x, gas)) + .collect::, _>>()?; + Ok(AscTagArray(Array::new(&*content, heap, gas)?)) } } -impl ToAscObj for codec::AccessKey { +impl ToAscObj for codec::ProofOfAccess { fn to_asc_obj( &self, heap: &mut H, gas: &GasCounter, - ) -> Result { - Ok(AscAccessKey { - nonce: self.nonce, - permission: asc_new(heap, self.permission.as_ref().unwrap(), gas)?, - _padding: 0, + ) -> Result { + Ok(AscProofOfAccess { + option: asc_new(heap, &self.option, gas)?, + tx_path: asc_new(heap, self.tx_path.as_slice(), gas)?, + data_path: asc_new(heap, self.data_path.as_slice(), gas)?, + chunk: asc_new(heap, self.chunk.as_slice(), gas)?, }) } } -impl ToAscObj for codec::AccessKeyPermission { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let (kind, payload) = match self.permission.as_ref().unwrap() { - codec::access_key_permission::Permission::FunctionCall(permission) => ( - AscAccessKeyPermissionKind::FunctionCall, - asc_new(heap, permission, gas)?.to_payload(), - ), - codec::access_key_permission::Permission::FullAccess(permission) => ( - AscAccessKeyPermissionKind::FullAccess, - asc_new(heap, permission, gas)?.to_payload(), - ), - }; - - Ok(AscAccessKeyPermissionEnum(AscEnum { - _padding: 0, - kind, - payload: EnumPayload(payload), - })) - } -} - -impl ToAscObj for codec::FunctionCallPermission { +impl ToAscObj for codec::Transaction { fn to_asc_obj( &self, heap: &mut H, gas: &GasCounter, - ) -> Result { - Ok(AscFunctionCallPermission { - // The `allowance` field is one of the few fields that can actually be None for real - allowance: match self.allowance.as_ref() { - Some(allowance) => asc_new(heap, allowance, gas)?, - None => AscPtr::null(), - }, - receiver_id: asc_new(heap, &self.receiver_id, gas)?, - method_names: asc_new(heap, &self.method_names, gas)?, + ) -> Result { + Ok(AscTransaction { + format: self.format, + id: asc_new(heap, &self.id, gas)?, + last_tx: asc_new(heap, self.last_tx.as_slice(), gas)?, + owner: asc_new(heap, self.owner.as_slice(), gas)?, + tags: asc_new(heap, &self.tags, gas)?, + target: asc_new(heap, self.target.as_slice(), gas)?, + quantity: asc_new(heap, &self.quantity, gas)?, + data: asc_new(heap, self.data.as_slice(), gas)?, + data_size: asc_new(heap, &self.data_size, gas)?, + data_root: asc_new(heap, self.data_root.as_slice(), gas)?, + signature: asc_new(heap, self.signature.as_slice(), gas)?, + reward: asc_new(heap, &self.reward, gas)?, }) } } -impl ToAscObj for codec::FullAccessPermission { - fn to_asc_obj( - &self, - _heap: &mut H, - _gas: &GasCounter, - ) -> Result { - Ok(AscFullAccessPermission {}) - } -} - -impl ToAscObj for codec::DeleteKeyAction { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscDeleteKeyAction { - public_key: asc_new(heap, self.public_key.as_ref().unwrap(), gas)?, - }) - } -} - -impl ToAscObj for codec::DeleteAccountAction { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscDeleteAccountAction { - beneficiary_id: asc_new(heap, &self.beneficiary_id, gas)?, - }) - } -} - -impl ToAscObj for codec::DataReceiver { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscDataReceiver { - data_id: asc_new(heap, self.data_id.as_ref().unwrap(), gas)?, - receiver_id: asc_new(heap, &self.receiver_id, gas)?, - }) - } -} - -impl ToAscObj for Vec { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); - let content = content?; - Ok(AscDataReceiverArray(Array::new(&*content, heap, gas)?)) - } -} - -impl ToAscObj for codec::ExecutionOutcomeWithId { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let outcome = self.outcome.as_ref().unwrap(); - - Ok(AscExecutionOutcome { - proof: asc_new(heap, &self.proof.as_ref().unwrap().path, gas)?, - block_hash: asc_new(heap, self.block_hash.as_ref().unwrap(), gas)?, - id: asc_new(heap, self.id.as_ref().unwrap(), gas)?, - logs: asc_new(heap, &outcome.logs, gas)?, - receipt_ids: asc_new(heap, &outcome.receipt_ids, gas)?, - gas_burnt: outcome.gas_burnt, - tokens_burnt: asc_new(heap, outcome.tokens_burnt.as_ref().unwrap(), gas)?, - executor_id: asc_new(heap, &outcome.executor_id, gas)?, - status: asc_new(heap, outcome.status.as_ref().unwrap(), gas)?, - }) - } -} - -impl ToAscObj for codec::execution_outcome::Status { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let (kind, payload) = match self { - codec::execution_outcome::Status::SuccessValue(value) => { - let bytes = &value.value; - - ( - AscSuccessStatusKind::Value, - asc_new(heap, bytes.as_slice(), gas)?.to_payload(), - ) - } - codec::execution_outcome::Status::SuccessReceiptId(receipt_id) => ( - AscSuccessStatusKind::ReceiptId, - asc_new(heap, receipt_id.id.as_ref().unwrap(), gas)?.to_payload(), - ), - codec::execution_outcome::Status::Failure(_) => { - return Err(DeterministicHostError::from(anyhow!( - "Failure execution status are not allowed" - ))); - } - codec::execution_outcome::Status::Unknown(_) => { - return Err(DeterministicHostError::from(anyhow!( - "Unknown execution status are not allowed" - ))); - } - }; - - Ok(AscSuccessStatusEnum(AscEnum { - _padding: 0, - kind, - payload: EnumPayload(payload), - })) - } -} - -impl ToAscObj for codec::MerklePathItem { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscMerklePathItem { - hash: asc_new(heap, self.hash.as_ref().unwrap(), gas)?, - direction: match self.direction { - 0 => AscDirection::Left, - 1 => AscDirection::Right, - x => { - return Err(DeterministicHostError::from(anyhow!( - "Invalid direction value {}", - x - ))) - } - }, - }) - } -} - -impl ToAscObj for Vec { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); - let content = content?; - Ok(AscMerklePathItemArray(Array::new(&*content, heap, gas)?)) - } -} - -impl ToAscObj for codec::Signature { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscSignature { - kind: match self.r#type { - 0 => 0, - 1 => 1, - value => { - return Err(DeterministicHostError::from(anyhow!( - "Invalid signature type {}", - value, - ))) - } - }, - bytes: asc_new(heap, self.bytes.as_slice(), gas)?, - }) - } -} - -impl ToAscObj for Vec { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); - let content = content?; - Ok(AscSignatureArray(Array::new(&*content, heap, gas)?)) - } -} - -impl ToAscObj for codec::PublicKey { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscPublicKey { - kind: match self.r#type { - 0 => 0, - 1 => 1, - value => { - return Err(DeterministicHostError::from(anyhow!( - "Invalid public key type {}", - value, - ))) - } - }, - bytes: asc_new(heap, self.bytes.as_slice(), gas)?, - }) - } -} - -impl ToAscObj for codec::ValidatorStake { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - Ok(AscValidatorStake { - account_id: asc_new(heap, &self.account_id, gas)?, - public_key: asc_new(heap, self.public_key.as_ref().unwrap(), gas)?, - stake: asc_new(heap, self.stake.as_ref().unwrap(), gas)?, - }) - } -} - -impl ToAscObj for Vec { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); - let content = content?; - Ok(AscValidatorStakeArray(Array::new(&*content, heap, gas)?)) - } -} - -impl ToAscObj for codec::SlashedValidator { +impl ToAscObj for codec::Block { fn to_asc_obj( &self, heap: &mut H, gas: &GasCounter, - ) -> Result { - Ok(AscSlashedValidator { - account_id: asc_new(heap, &self.account_id, gas)?, - is_double_sign: self.is_double_sign, + ) -> Result { + Ok(AscBlock { + indep_hash: self.height, + nonce: asc_new(heap, self.nonce.as_slice(), gas)?, + previous_block: asc_new(heap, self.previous_block.as_slice(), gas)?, + timestamp: self.timestamp, + last_retarget: self.last_retarget, + diff: asc_new(heap, &self.diff, gas)?, + height: self.height, + hash: asc_new(heap, self.hash.as_slice(), gas)?, + tx_root: self + .tx_root + .map(|tx_root| asc_new(heap, tx_root.as_slice(), gas)) + .unwrap_or(Ok(AscPtr::null()))?, + wallet_list: asc_new(heap, self.wallet_list.as_slice(), gas)?, + reward_addr: asc_new(heap, self.reward_addr.as_slice(), gas)?, + tags: asc_new(heap, &self.tags, gas)?, + reward_pool: asc_new(heap, &self.reward_pool, gas)?, + weave_size: asc_new(heap, &self.weave_size, gas)?, + block_size: asc_new(heap, &self.block_size, gas)?, + cumulative_diff: self + .cumulative_diff + .map(|cumulative_diff| asc_new(heap, &cumulative_diff, gas)) + .unwrap_or(Ok(AscPtr::null()))?, + hash_list_merkle: self + .hash_list_merkle + .map(|hash_list_merkle| asc_new(heap, hash_list_merkle.as_slice(), gas)) + .unwrap_or(Ok(AscPtr::null()))?, + poa: self + .poa + .as_ref() + .map(|poa| asc_new(heap, poa, gas)) + .unwrap_or(Ok(AscPtr::null()))?, }) } } - -impl ToAscObj for Vec { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); - let content = content?; - Ok(AscSlashedValidatorArray(Array::new(&*content, heap, gas)?)) - } -} - -impl ToAscObj for codec::CryptoHash { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - self.bytes.to_asc_obj(heap, gas) - } -} - -impl ToAscObj for Vec { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - let content: Result, _> = self.iter().map(|x| asc_new(heap, x, gas)).collect(); - let content = content?; - Ok(AscCryptoHashArray(Array::new(&*content, heap, gas)?)) - } -} - -impl ToAscObj for codec::BigInt { - fn to_asc_obj( - &self, - heap: &mut H, - gas: &GasCounter, - ) -> Result { - // Bytes are reversed to align with BigInt bytes endianess - let reversed: Vec = self.bytes.iter().rev().map(|x| *x).collect(); - - reversed.to_asc_obj(heap, gas) - } -} diff --git a/chain/arweave/src/runtime/generated.rs b/chain/arweave/src/runtime/generated.rs index f1d7e0bdb02..104bbe2c40e 100644 --- a/chain/arweave/src/runtime/generated.rs +++ b/chain/arweave/src/runtime/generated.rs @@ -3,444 +3,83 @@ use graph::runtime::{ }; use graph::semver::Version; use graph_runtime_derive::AscType; -use graph_runtime_wasm::asc_abi::class::{Array, AscBigInt, AscEnum, AscString, Uint8Array}; +use graph_runtime_wasm::asc_abi::class::{Array, AscEnum, AscString, Uint8Array}; -pub(crate) type AscCryptoHash = Uint8Array; -pub(crate) type AscAccountId = AscString; -pub(crate) type AscBlockHeight = u64; -pub(crate) type AscBalance = AscBigInt; -pub(crate) type AscGas = u64; -pub(crate) type AscShardId = u64; -pub(crate) type AscNumBlocks = u64; -pub(crate) type AscProtocolVersion = u32; - -pub struct AscDataReceiverArray(pub(crate) Array>); - -impl AscType for AscDataReceiverArray { - fn to_asc_bytes(&self) -> Result, DeterministicHostError> { - self.0.to_asc_bytes() - } - - fn from_asc_bytes( - asc_obj: &[u8], - api_version: &Version, - ) -> Result { - Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) - } -} - -impl AscIndexId for AscDataReceiverArray { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayDataReceiver; -} - -pub struct AscCryptoHashArray(pub(crate) Array>); - -impl AscType for AscCryptoHashArray { - fn to_asc_bytes(&self) -> Result, DeterministicHostError> { - self.0.to_asc_bytes() - } - - fn from_asc_bytes( - asc_obj: &[u8], - api_version: &Version, - ) -> Result { - Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) - } -} - -impl AscIndexId for AscCryptoHashArray { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayCryptoHash; -} - -pub struct AscActionEnumArray(pub(crate) Array>); - -impl AscType for AscActionEnumArray { - fn to_asc_bytes(&self) -> Result, DeterministicHostError> { - self.0.to_asc_bytes() - } - - fn from_asc_bytes( - asc_obj: &[u8], - api_version: &Version, - ) -> Result { - Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) - } -} - -impl AscIndexId for AscActionEnumArray { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayActionEnum; -} - -pub struct AscMerklePathItemArray(pub(crate) Array>); - -impl AscType for AscMerklePathItemArray { - fn to_asc_bytes(&self) -> Result, DeterministicHostError> { - self.0.to_asc_bytes() - } - - fn from_asc_bytes( - asc_obj: &[u8], - api_version: &Version, - ) -> Result { - Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) - } -} - -impl AscIndexId for AscMerklePathItemArray { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayMerklePathItem; -} - -pub struct AscValidatorStakeArray(pub(crate) Array>); - -impl AscType for AscValidatorStakeArray { - fn to_asc_bytes(&self) -> Result, DeterministicHostError> { - self.0.to_asc_bytes() - } - - fn from_asc_bytes( - asc_obj: &[u8], - api_version: &Version, - ) -> Result { - Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) - } -} - -impl AscIndexId for AscValidatorStakeArray { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayValidatorStake; -} - -pub struct AscSlashedValidatorArray(pub(crate) Array>); - -impl AscType for AscSlashedValidatorArray { - fn to_asc_bytes(&self) -> Result, DeterministicHostError> { - self.0.to_asc_bytes() - } - - fn from_asc_bytes( - asc_obj: &[u8], - api_version: &Version, - ) -> Result { - Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) - } -} - -impl AscIndexId for AscSlashedValidatorArray { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArraySlashedValidator; -} - -pub struct AscSignatureArray(pub(crate) Array>); - -impl AscType for AscSignatureArray { - fn to_asc_bytes(&self) -> Result, DeterministicHostError> { - self.0.to_asc_bytes() - } - - fn from_asc_bytes( - asc_obj: &[u8], - api_version: &Version, - ) -> Result { - Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) - } -} - -impl AscIndexId for AscSignatureArray { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArraySignature; -} - -pub struct AscChunkHeaderArray(pub(crate) Array>); - -impl AscType for AscChunkHeaderArray { - fn to_asc_bytes(&self) -> Result, DeterministicHostError> { - self.0.to_asc_bytes() - } - - fn from_asc_bytes( - asc_obj: &[u8], - api_version: &Version, - ) -> Result { - Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) - } -} - -impl AscIndexId for AscChunkHeaderArray { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearArrayChunkHeader; -} - -pub struct AscAccessKeyPermissionEnum(pub(crate) AscEnum); - -impl AscType for AscAccessKeyPermissionEnum { - fn to_asc_bytes(&self) -> Result, DeterministicHostError> { - self.0.to_asc_bytes() - } - - fn from_asc_bytes( - asc_obj: &[u8], - api_version: &Version, - ) -> Result { - Ok(Self(AscEnum::from_asc_bytes(asc_obj, api_version)?)) - } -} - -impl AscIndexId for AscAccessKeyPermissionEnum { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearAccessKeyPermissionEnum; -} - -pub struct AscActionEnum(pub(crate) AscEnum); - -impl AscType for AscActionEnum { - fn to_asc_bytes(&self) -> Result, DeterministicHostError> { - self.0.to_asc_bytes() - } - - fn from_asc_bytes( - asc_obj: &[u8], - api_version: &Version, - ) -> Result { - Ok(Self(AscEnum::from_asc_bytes(asc_obj, api_version)?)) - } -} - -impl AscIndexId for AscActionEnum { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearActionEnum; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscPublicKey { - pub kind: u32, - pub bytes: AscPtr, -} - -impl AscIndexId for AscPublicKey { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearPublicKey; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscSignature { - pub kind: u32, - pub bytes: AscPtr, -} - -impl AscIndexId for AscSignature { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearSignature; -} - -#[repr(u32)] -#[derive(AscType, Copy, Clone)] -pub(crate) enum AscAccessKeyPermissionKind { - FunctionCall, - FullAccess, -} - -impl AscValue for AscAccessKeyPermissionKind {} - -impl Default for AscAccessKeyPermissionKind { - fn default() -> Self { - Self::FunctionCall - } -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscFunctionCallPermission { - pub allowance: AscPtr, - pub receiver_id: AscPtr, - pub method_names: AscPtr>>, -} - -impl AscIndexId for AscFunctionCallPermission { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearFunctionCallPermission; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscFullAccessPermission {} - -impl AscIndexId for AscFullAccessPermission { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearFullAccessPermission; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscAccessKey { - pub nonce: u64, - pub permission: AscPtr, - - // It seems that is impossible to correctly order fields in this struct - // so that Rust packs it tighly without padding. So we add 4 bytes of padding - // ourself. - // - // This is a bit problematic because AssemblyScript actually is ok with 12 bytes - // and is fully packed. Seems like a differences between alignment for `repr(C)` and - // AssemblyScript. - pub(crate) _padding: u32, -} - -impl AscIndexId for AscAccessKey { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearAccessKey; -} +// #[repr(C)] +// #[derive(AscType)] +// pub struct AscBlock { +// pub indep_hash: AscPtr, +// pub nonce: AscPtr, +// pub previous_block: AscPtr, +// pub timestamp: u64, +// pub last_retarget: u64, +// pub diff: AscPtr, +// pub height: u64, +// pub hash: AscPtr, +// pub tx_root: AscPtr>, +// pub wallet_list: AscPtr, +// pub reward_addr: AscPtr, +// pub tags: AscPtr>, +// pub reward_pool: AscPtr, +// pub weave_size: AscPtr, +// pub block_size: AscPtr, +// pub cumulative_diff: AscPtr, +// pub hash_list_merkle: AscPtr>, +// pub poa: AscPtr, +// } +// +// impl AscIndexId for AscBlock { +// const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::ArweaveBlock; +// } #[repr(C)] #[derive(AscType)] -pub(crate) struct AscDataReceiver { - pub data_id: AscPtr, - pub receiver_id: AscPtr, +pub struct AscProofOfAccess { + pub option: AscPtr, + pub tx_path: AscPtr, + pub data_path: AscPtr, + pub chunk: AscPtr, } -impl AscIndexId for AscDataReceiver { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearDataReceiver; -} - -#[repr(u32)] -#[derive(AscType, Copy, Clone)] -pub(crate) enum AscActionKind { - CreateAccount, - DeployContract, - FunctionCall, - Transfer, - Stake, - AddKey, - DeleteKey, - DeleteAccount, -} - -impl AscValue for AscActionKind {} - -impl Default for AscActionKind { - fn default() -> Self { - Self::CreateAccount - } +impl AscIndexId for AscProofOfAccess { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::ArweaveProofOfAccess; } #[repr(C)] #[derive(AscType)] -pub(crate) struct AscCreateAccountAction {} - -impl AscIndexId for AscCreateAccountAction { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearCreateAccountAction; +pub struct AscTransaction { + pub format: u32, + pub id: AscPtr, + pub last_tx: AscPtr, + pub owner: AscPtr, + pub tags: AscPtr, + pub target: AscPtr, + pub quantity: AscPtr, + pub data: AscPtr, + pub data_size: AscPtr, + pub data_root: AscPtr, + pub signature: AscPtr, + pub reward: AscPtr, } -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscDeployContractAction { - pub code: AscPtr, -} - -impl AscIndexId for AscDeployContractAction { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearDeployContractAction; +impl AscIndexId for AscTransaction { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::ArweaveTransaction; } #[repr(C)] #[derive(AscType)] -pub(crate) struct AscFunctionCallAction { - pub method_name: AscPtr, - pub args: AscPtr, - pub gas: u64, - pub deposit: AscPtr, - - // It seems that is impossible to correctly order fields in this struct - // so that Rust packs it tighly without padding. So we add 4 bytes of padding - // ourself. - // - // This is a bit problematic because AssemblyScript actually is ok with 20 bytes - // and is fully packed. Seems like a differences between alignment for `repr(C)` and - // AssemblyScript. - pub(crate) _padding: u32, +pub struct AscTag { + pub name: AscPtr, + pub value: AscPtr, } -impl AscIndexId for AscFunctionCallAction { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearFunctionCallAction; +impl AscIndexId for AscTag { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::ArweaveTag; } -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscTransferAction { - pub deposit: AscPtr, -} +pub struct AscTagArray(pub(crate) Array>); -impl AscIndexId for AscTransferAction { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearTransferAction; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscStakeAction { - pub stake: AscPtr, - pub public_key: AscPtr, -} - -impl AscIndexId for AscStakeAction { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearStakeAction; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscAddKeyAction { - pub public_key: AscPtr, - pub access_key: AscPtr, -} - -impl AscIndexId for AscAddKeyAction { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearAddKeyAction; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscDeleteKeyAction { - pub public_key: AscPtr, -} - -impl AscIndexId for AscDeleteKeyAction { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearDeleteKeyAction; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscDeleteAccountAction { - pub beneficiary_id: AscPtr, -} - -impl AscIndexId for AscDeleteAccountAction { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearDeleteAccountAction; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscActionReceipt { - pub predecessor_id: AscPtr, - pub receiver_id: AscPtr, - pub id: AscPtr, - pub signer_id: AscPtr, - pub signer_public_key: AscPtr, - pub gas_price: AscPtr, - pub output_data_receivers: AscPtr, - pub input_data_ids: AscPtr, - pub actions: AscPtr, -} - -impl AscIndexId for AscActionReceipt { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearActionReceipt; -} - -#[repr(u32)] -#[derive(AscType, Copy, Clone)] -pub(crate) enum AscSuccessStatusKind { - Value, - ReceiptId, -} - -impl AscValue for AscSuccessStatusKind {} - -impl Default for AscSuccessStatusKind { - fn default() -> Self { - Self::Value - } -} - -pub struct AscSuccessStatusEnum(pub(crate) AscEnum); - -impl AscType for AscSuccessStatusEnum { +impl AscType for AscTagArray { fn to_asc_bytes(&self) -> Result, DeterministicHostError> { self.0.to_asc_bytes() } @@ -449,172 +88,10 @@ impl AscType for AscSuccessStatusEnum { asc_obj: &[u8], api_version: &Version, ) -> Result { - Ok(Self(AscEnum::from_asc_bytes(asc_obj, api_version)?)) - } -} - -impl AscIndexId for AscSuccessStatusEnum { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearSuccessStatusEnum; -} - -#[repr(u32)] -#[derive(AscType, Copy, Clone)] -pub(crate) enum AscDirection { - Left, - Right, -} - -impl AscValue for AscDirection {} - -impl Default for AscDirection { - fn default() -> Self { - Self::Left + Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) } } -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscMerklePathItem { - pub hash: AscPtr, - pub direction: AscDirection, -} - -impl AscIndexId for AscMerklePathItem { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearMerklePathItem; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscExecutionOutcome { - pub gas_burnt: u64, - pub proof: AscPtr, - pub block_hash: AscPtr, - pub id: AscPtr, - pub logs: AscPtr>>, - pub receipt_ids: AscPtr, - pub tokens_burnt: AscPtr, - pub executor_id: AscPtr, - pub status: AscPtr, -} - -impl AscIndexId for AscExecutionOutcome { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearExecutionOutcome; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscSlashedValidator { - pub account_id: AscPtr, - pub is_double_sign: bool, -} - -impl AscIndexId for AscSlashedValidator { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearSlashedValidator; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscBlockHeader { - pub height: AscBlockHeight, - pub prev_height: AscBlockHeight, - pub block_ordinal: AscNumBlocks, - pub epoch_id: AscPtr, - pub next_epoch_id: AscPtr, - pub chunks_included: u64, - pub hash: AscPtr, - pub prev_hash: AscPtr, - pub timestamp_nanosec: u64, - pub prev_state_root: AscPtr, - pub chunk_receipts_root: AscPtr, - pub chunk_headers_root: AscPtr, - pub chunk_tx_root: AscPtr, - pub outcome_root: AscPtr, - pub challenges_root: AscPtr, - pub random_value: AscPtr, - pub validator_proposals: AscPtr, - pub chunk_mask: AscPtr>, - pub gas_price: AscPtr, - pub total_supply: AscPtr, - pub challenges_result: AscPtr, - pub last_final_block: AscPtr, - pub last_ds_final_block: AscPtr, - pub next_bp_hash: AscPtr, - pub block_merkle_root: AscPtr, - pub epoch_sync_data_hash: AscPtr, - pub approvals: AscPtr, - pub signature: AscPtr, - pub latest_protocol_version: AscProtocolVersion, -} - -impl AscIndexId for AscBlockHeader { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearBlockHeader; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscValidatorStake { - pub account_id: AscPtr, - pub public_key: AscPtr, - pub stake: AscPtr, -} - -impl AscIndexId for AscValidatorStake { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearValidatorStake; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscChunkHeader { - pub encoded_length: u64, - pub gas_used: AscGas, - pub gas_limit: AscGas, - pub shard_id: AscShardId, - pub height_created: AscBlockHeight, - pub height_included: AscBlockHeight, - pub chunk_hash: AscPtr, - pub signature: AscPtr, - pub prev_block_hash: AscPtr, - pub prev_state_root: AscPtr, - pub encoded_merkle_root: AscPtr, - pub balance_burnt: AscPtr, - pub outgoing_receipts_root: AscPtr, - pub tx_root: AscPtr, - pub validator_proposals: AscPtr, - - // It seems that is impossible to correctly order fields in this struct - // so that Rust packs it tighly without padding. So we add 4 bytes of padding - // ourself. - // - // This is a bit problematic because AssemblyScript actually is ok with 84 bytes - // and is fully packed. Seems like a differences between alignment for `repr(C)` and - // AssemblyScript. - pub(crate) _padding: u32, -} - -impl AscIndexId for AscChunkHeader { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearChunkHeader; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscBlock { - pub author: AscPtr, - pub header: AscPtr, - pub chunks: AscPtr, -} - -impl AscIndexId for AscBlock { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearBlock; -} - -#[repr(C)] -#[derive(AscType)] -pub(crate) struct AscReceiptWithOutcome { - pub outcome: AscPtr, - pub receipt: AscPtr, - pub block: AscPtr, -} - -impl AscIndexId for AscReceiptWithOutcome { - const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::NearReceiptWithOutcome; +impl AscIndexId for AscTagArray { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::ArweaveTagArray; } diff --git a/graph/src/blockchain/mod.rs b/graph/src/blockchain/mod.rs index 4da48521957..16bf472bd2e 100644 --- a/graph/src/blockchain/mod.rs +++ b/graph/src/blockchain/mod.rs @@ -307,6 +307,9 @@ pub trait NodeCapabilities { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] pub enum BlockchainKind { + /// Arweave chains that are compatible. + Arweave, + /// Ethereum itself or chains that are compatible. Ethereum, @@ -320,6 +323,7 @@ pub enum BlockchainKind { impl fmt::Display for BlockchainKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let value = match self { + BlockchainKind::Arweave => "arweave", BlockchainKind::Ethereum => "ethereum", BlockchainKind::Near => "near", BlockchainKind::Tendermint => "tendermint", diff --git a/graph/src/runtime/mod.rs b/graph/src/runtime/mod.rs index 644488072da..5a8e45bfe45 100644 --- a/graph/src/runtime/mod.rs +++ b/graph/src/runtime/mod.rs @@ -320,7 +320,20 @@ pub enum IndexForAscTypeId { // ... // LastTendermintType = 2499, - // Reserved discriminant space for a future blockchain type IDs: [2,500, 3,499] + // Arweave types + ArweaveBlock = 2500, + ArweaveProofOfAccess = 2501, + ArweaveTransaction = 2502, + ArweaveTag = 2503, + ArweaveTagArray = 2504, + // Continue to add more Tendermint type IDs here. + // e.g.: + // NextArweaveType = 2505, + // AnotherArweaveType = 2506, + // ... + // LastArweaveType = 3499, + + // Reserved discriminant space for a future blockchain type IDs: [3,500, 4,499] // // Generated with the following shell script: // @@ -331,7 +344,7 @@ pub enum IndexForAscTypeId { // INSTRUCTIONS: // 1. Replace the IDENTIFIER_PREFIX and the SRC_FILE placeholders according to the blockchain // name and implementation before running this script. - // 2. Replace `2500` part with the first number of that blockchain's reserved discriminant space. + // 2. Replace `3500` part with the first number of that blockchain's reserved discriminant space. // 3. Insert the output right before the end of this block. } From 9b3930613140d1509c70aacf4d925a9bc6cfc525 Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Mon, 11 Apr 2022 14:35:37 +0800 Subject: [PATCH 03/19] feat(chain): add runtime abi for arweave block --- chain/arweave/src/runtime/abi.rs | 2 +- chain/arweave/src/runtime/generated.rs | 52 +++++++++++++------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/chain/arweave/src/runtime/abi.rs b/chain/arweave/src/runtime/abi.rs index b8fe94c7956..703fc126093 100644 --- a/chain/arweave/src/runtime/abi.rs +++ b/chain/arweave/src/runtime/abi.rs @@ -79,7 +79,7 @@ impl ToAscObj for codec::Block { gas: &GasCounter, ) -> Result { Ok(AscBlock { - indep_hash: self.height, + indep_hash: asc_new(heap, self.indep_hash.as_slice(), gas)?, nonce: asc_new(heap, self.nonce.as_slice(), gas)?, previous_block: asc_new(heap, self.previous_block.as_slice(), gas)?, timestamp: self.timestamp, diff --git a/chain/arweave/src/runtime/generated.rs b/chain/arweave/src/runtime/generated.rs index 104bbe2c40e..ce4ce788b59 100644 --- a/chain/arweave/src/runtime/generated.rs +++ b/chain/arweave/src/runtime/generated.rs @@ -5,32 +5,32 @@ use graph::semver::Version; use graph_runtime_derive::AscType; use graph_runtime_wasm::asc_abi::class::{Array, AscEnum, AscString, Uint8Array}; -// #[repr(C)] -// #[derive(AscType)] -// pub struct AscBlock { -// pub indep_hash: AscPtr, -// pub nonce: AscPtr, -// pub previous_block: AscPtr, -// pub timestamp: u64, -// pub last_retarget: u64, -// pub diff: AscPtr, -// pub height: u64, -// pub hash: AscPtr, -// pub tx_root: AscPtr>, -// pub wallet_list: AscPtr, -// pub reward_addr: AscPtr, -// pub tags: AscPtr>, -// pub reward_pool: AscPtr, -// pub weave_size: AscPtr, -// pub block_size: AscPtr, -// pub cumulative_diff: AscPtr, -// pub hash_list_merkle: AscPtr>, -// pub poa: AscPtr, -// } -// -// impl AscIndexId for AscBlock { -// const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::ArweaveBlock; -// } +#[repr(C)] +#[derive(AscType)] +pub struct AscBlock { + pub indep_hash: AscPtr, + pub nonce: AscPtr, + pub previous_block: AscPtr, + pub timestamp: u64, + pub last_retarget: u64, + pub diff: AscPtr, + pub height: u64, + pub hash: AscPtr, + pub tx_root: AscPtr, + pub wallet_list: AscPtr, + pub reward_addr: AscPtr, + pub tags: AscPtr, + pub reward_pool: AscPtr, + pub weave_size: AscPtr, + pub block_size: AscPtr, + pub cumulative_diff: AscPtr, + pub hash_list_merkle: AscPtr, + pub poa: AscPtr, +} + +impl AscIndexId for AscBlock { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::ArweaveBlock; +} #[repr(C)] #[derive(AscType)] From ebfb4e1ea2de3132c692af8b74954976a6e55ca3 Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Mon, 11 Apr 2022 14:54:20 +0800 Subject: [PATCH 04/19] feat(chain): implement BlockChain trait for Arweave --- chain/arweave/src/adapter.rs | 156 +-------- chain/arweave/src/capabilities.rs | 2 +- chain/arweave/src/chain.rs | 223 ++----------- chain/arweave/src/codec.rs | 107 +----- chain/arweave/src/data_source.rs | 67 +--- chain/arweave/src/lib.rs | 1 - chain/arweave/src/runtime/abi.rs | 7 +- chain/arweave/src/runtime/generated.rs | 6 +- chain/arweave/src/trigger.rs | 430 ++----------------------- 9 files changed, 81 insertions(+), 918 deletions(-) diff --git a/chain/arweave/src/adapter.rs b/chain/arweave/src/adapter.rs index 33c47e9bc51..41f6a69743f 100644 --- a/chain/arweave/src/adapter.rs +++ b/chain/arweave/src/adapter.rs @@ -1,5 +1,3 @@ -use std::collections::HashSet; - use crate::capabilities::NodeCapabilities; use crate::{data_source::DataSource, Chain}; use graph::blockchain as bc; @@ -9,23 +7,18 @@ use prost::Message; use prost_types::Any; const BASIC_RECEIPT_FILTER_TYPE_URL: &str = - "type.googleapis.com/sf.near.transform.v1.BasicReceiptFilter"; + "type.googleapis.com/sf.arweave.transform.v1.BasicReceiptFilter"; #[derive(Clone, Debug, Default)] pub struct TriggerFilter { - pub(crate) block_filter: NearBlockFilter, - pub(crate) receipt_filter: NearReceiptFilter, + pub(crate) block_filter: ArweaveBlockFilter, } impl bc::TriggerFilter for TriggerFilter { fn extend<'a>(&mut self, data_sources: impl Iterator + Clone) { - let TriggerFilter { - block_filter, - receipt_filter, - } = self; + let TriggerFilter { block_filter } = self; - block_filter.extend(NearBlockFilter::from_data_sources(data_sources.clone())); - receipt_filter.extend(NearReceiptFilter::from_data_sources(data_sources)); + block_filter.extend(ArweaveBlockFilter::from_data_sources(data_sources)); } fn node_capabilities(&self) -> NodeCapabilities { @@ -41,20 +34,16 @@ impl bc::TriggerFilter for TriggerFilter { fn to_firehose_filter(self) -> Vec { let TriggerFilter { block_filter: block, - receipt_filter: receipt, } = self; if block.trigger_every_block { return vec![]; } - if receipt.is_empty() { - return vec![]; - } - - let filter = BasicReceiptFilter { - accounts: receipt.accounts.into_iter().collect(), - }; + // # NOTE + // + // Arweave don't have receipts + let filter = BasicReceiptFilter { accounts: vec![] }; vec![Any { type_url: BASIC_RECEIPT_FILTER_TYPE_URL.into(), @@ -63,54 +52,14 @@ impl bc::TriggerFilter for TriggerFilter { } } -pub(crate) type Account = String; - -/// NearReceiptFilter requires the account to be set, it will match every receipt where `source.account` is the recipient. -/// see docs: https://thegraph.com/docs/en/supported-networks/near/ -#[derive(Clone, Debug, Default)] -pub(crate) struct NearReceiptFilter { - pub accounts: HashSet, -} - -impl NearReceiptFilter { - pub fn matches(&self, account: &String) -> bool { - self.accounts.contains(account) - } - - pub fn is_empty(&self) -> bool { - let NearReceiptFilter { accounts } = self; - - accounts.is_empty() - } - - pub fn from_data_sources<'a>(iter: impl IntoIterator) -> Self { - let accounts: Vec = iter - .into_iter() - .filter(|data_source| { - data_source.source.account.is_some() - && !data_source.mapping.receipt_handlers.is_empty() - }) - .map(|ds| ds.source.account.as_ref().unwrap().clone()) - .collect(); - - Self { - accounts: HashSet::from_iter(accounts), - } - } - - pub fn extend(&mut self, other: NearReceiptFilter) { - self.accounts.extend(other.accounts); - } -} - -/// NearBlockFilter will match every block regardless of source being set. -/// see docs: https://thegraph.com/docs/en/supported-networks/near/ +/// ArweaveBlockFilter will match every block regardless of source being set. +/// see docs: https://thegraph.com/docs/en/supported-networks/arweave/ #[derive(Clone, Debug, Default)] -pub(crate) struct NearBlockFilter { +pub(crate) struct ArweaveBlockFilter { pub trigger_every_block: bool, } -impl NearBlockFilter { +impl ArweaveBlockFilter { pub fn from_data_sources<'a>(iter: impl IntoIterator) -> Self { Self { trigger_every_block: iter @@ -119,86 +68,7 @@ impl NearBlockFilter { } } - pub fn extend(&mut self, other: NearBlockFilter) { + pub fn extend(&mut self, other: ArweaveBlockFilter) { self.trigger_every_block = self.trigger_every_block || other.trigger_every_block; } } - -#[cfg(test)] -mod test { - use std::collections::HashSet; - - use super::NearBlockFilter; - use crate::adapter::{TriggerFilter, BASIC_RECEIPT_FILTER_TYPE_URL}; - use graph::{blockchain::TriggerFilter as _, firehose::BasicReceiptFilter}; - use prost::Message; - use prost_types::Any; - - #[test] - fn near_trigger_empty_filter() { - let filter = TriggerFilter { - block_filter: NearBlockFilter { - trigger_every_block: false, - }, - receipt_filter: super::NearReceiptFilter { - accounts: HashSet::new(), - }, - }; - assert_eq!(filter.to_firehose_filter(), vec![]); - } - - #[test] - fn near_trigger_filter_match_all_block() { - let filter = TriggerFilter { - block_filter: NearBlockFilter { - trigger_every_block: true, - }, - receipt_filter: super::NearReceiptFilter { - accounts: HashSet::from_iter(vec!["acc1".into(), "acc2".into(), "acc3".into()]), - }, - }; - - let filter = filter.to_firehose_filter(); - assert_eq!(filter.len(), 0); - } - - #[test] - fn near_trigger_filter() { - let filter = TriggerFilter { - block_filter: NearBlockFilter { - trigger_every_block: false, - }, - receipt_filter: super::NearReceiptFilter { - accounts: HashSet::from_iter(vec!["acc1".into(), "acc2".into(), "acc3".into()]), - }, - }; - - let filter = filter.to_firehose_filter(); - assert_eq!(filter.len(), 1); - - let firehose_filter = decode_filter(filter); - - assert_eq!( - firehose_filter.accounts, - vec![ - String::from("acc1"), - String::from("acc2"), - String::from("acc3") - ], - ); - } - - fn decode_filter(firehose_filter: Vec) -> BasicReceiptFilter { - let firehose_filter = firehose_filter[0].clone(); - assert_eq!( - firehose_filter.type_url, - String::from(BASIC_RECEIPT_FILTER_TYPE_URL), - ); - let mut bytes = &firehose_filter.value[..]; - let mut firehose_filter = - BasicReceiptFilter::decode(&mut bytes).expect("unable to parse basic receipt filter"); - firehose_filter.accounts.sort(); - - firehose_filter - } -} diff --git a/chain/arweave/src/capabilities.rs b/chain/arweave/src/capabilities.rs index 0d84c9c555d..27c7622aeb5 100644 --- a/chain/arweave/src/capabilities.rs +++ b/chain/arweave/src/capabilities.rs @@ -24,7 +24,7 @@ impl FromStr for NodeCapabilities { impl fmt::Display for NodeCapabilities { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("near") + f.write_str("arweave") } } diff --git a/chain/arweave/src/chain.rs b/chain/arweave/src/chain.rs index a472a78fe7c..c2cbe7bf235 100644 --- a/chain/arweave/src/chain.rs +++ b/chain/arweave/src/chain.rs @@ -1,4 +1,4 @@ -use graph::blockchain::BlockchainKind; +use graph::blockchain::{Block, BlockchainKind}; use graph::cheap_clone::CheapClone; use graph::data::subgraph::UnifiedMappingApiVersion; use graph::firehose::{FirehoseEndpoint, FirehoseEndpoints}; @@ -24,7 +24,7 @@ use crate::adapter::TriggerFilter; use crate::capabilities::NodeCapabilities; use crate::data_source::{DataSourceTemplate, UnresolvedDataSourceTemplate}; use crate::runtime::RuntimeAdapter; -use crate::trigger::{self, NearTrigger}; +use crate::trigger::ArweaveTrigger; use crate::{ codec, data_source::{DataSource, UnresolvedDataSource}, @@ -41,7 +41,7 @@ pub struct Chain { impl std::fmt::Debug for Chain { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "chain: near") + write!(f, "chain: arweave") } } @@ -65,7 +65,7 @@ impl Chain { #[async_trait] impl Blockchain for Chain { - const KIND: BlockchainKind = BlockchainKind::Near; + const KIND: BlockchainKind = BlockchainKind::Arweave; type Block = codec::Block; @@ -79,9 +79,9 @@ impl Blockchain for Chain { type TriggersAdapter = TriggersAdapter; - type TriggerData = crate::trigger::NearTrigger; + type TriggerData = crate::trigger::ArweaveTrigger; - type MappingTrigger = crate::trigger::NearTrigger; + type MappingTrigger = crate::trigger::ArweaveTrigger; type TriggerFilter = crate::adapter::TriggerFilter; @@ -148,7 +148,7 @@ impl Blockchain for Chain { _filter: Arc, _unified_api_version: UnifiedMappingApiVersion, ) -> Result>, Error> { - panic!("NEAR does not support polling block stream") + panic!("ARWEAVE does not support polling block stream") } fn chain_store(&self) -> Arc { @@ -166,7 +166,7 @@ impl Blockchain for Chain { }; firehose_endpoint - .block_ptr_for_number::(logger, number) + .block_ptr_for_number::(logger, number) .map_err(Into::into) .await } @@ -202,54 +202,12 @@ impl TriggersAdapterTrait for TriggersAdapter { // TODO: Find the best place to introduce an `Arc` and avoid this clone. let shared_block = Arc::new(block.clone()); - let TriggerFilter { - block_filter, - receipt_filter, - } = filter; - - // Filter non-successful or non-action receipts. - let receipts = block.shards.iter().flat_map(|shard| { - shard - .receipt_execution_outcomes - .iter() - .filter_map(|outcome| { - if !outcome - .execution_outcome - .as_ref()? - .outcome - .as_ref()? - .status - .as_ref()? - .is_success() - { - return None; - } - if !matches!( - outcome.receipt.as_ref()?.receipt, - Some(codec::receipt::Receipt::Action(_)) - ) { - return None; - } - - let receipt = outcome.receipt.as_ref()?.clone(); - if !receipt_filter.matches(&receipt.receiver_id) { - return None; - } - - Some(trigger::ReceiptWithOutcome { - outcome: outcome.execution_outcome.as_ref()?.clone(), - receipt, - block: shared_block.cheap_clone(), - }) - }) - }); + let TriggerFilter { block_filter } = filter; - let mut trigger_data: Vec<_> = receipts - .map(|r| NearTrigger::Receipt(Arc::new(r))) - .collect(); + let mut trigger_data: Vec = Vec::new(); if block_filter.trigger_every_block { - trigger_data.push(NearTrigger::Block(shared_block.cheap_clone())); + trigger_data.push(ArweaveTrigger::Block(shared_block.cheap_clone())); } Ok(BlockWithTriggers::new(block, trigger_data)) @@ -270,7 +228,7 @@ impl TriggersAdapterTrait for TriggersAdapter { /// Panics if `block` is genesis. /// But that's ok since this is only called when reverting `block`. async fn parent_ptr(&self, block: &BlockPtr) -> Result, Error> { - // FIXME (NEAR): Might not be necessary for NEAR support for now + // FIXME (ARWEAVE): Might not be necessary for ARWEAVE support for now Ok(Some(BlockPtr { hash: BlockHash::from(vec![0xff; 32]), number: block.number.saturating_sub(1), @@ -321,7 +279,6 @@ impl FirehoseMapperTrait for FirehoseMapper { StepUndo => { let parent_ptr = block - .header() .parent_ptr() .expect("Genesis block should never be reverted"); @@ -347,162 +304,18 @@ impl FirehoseMapperTrait for FirehoseMapper { number: BlockNumber, ) -> Result { self.endpoint - .block_ptr_for_number::(logger, number) + .block_ptr_for_number::(logger, number) .await } + // # FIXME + // + // the final block of arweave is itself in the current implementation async fn final_block_ptr_for( &self, - logger: &Logger, + _logger: &Logger, block: &codec::Block, ) -> Result { - let final_block_number = block.header().last_final_block_height as BlockNumber; - - self.endpoint - .block_ptr_for_number::(logger, final_block_number) - .await - } -} - -#[cfg(test)] -mod test { - use std::{collections::HashSet, vec}; - - use graph::{ - blockchain::{block_stream::BlockWithTriggers, TriggersAdapter as _}, - prelude::tokio, - slog::{self, o, Logger}, - }; - - use crate::{ - adapter::{NearReceiptFilter, TriggerFilter}, - codec::{ - self, execution_outcome, - receipt::{self}, - BlockHeader, DataReceiver, ExecutionOutcome, ExecutionOutcomeWithId, - IndexerExecutionOutcomeWithReceipt, IndexerShard, ReceiptAction, - SuccessValueExecutionStatus, - }, - Chain, - }; - - use super::TriggersAdapter; - - #[tokio::test] - async fn test_trigger_filter_empty() { - let account1: String = "account1".into(); - - let adapter = TriggersAdapter {}; - - let logger = Logger::root(slog::Discard, o!()); - let block1 = new_success_block(1, &account1); - - let filter = TriggerFilter::default(); - - let block_with_triggers: BlockWithTriggers = adapter - .triggers_in_block(&logger, block1, &filter) - .await - .expect("failed to execute triggers_in_block"); - assert_eq!(block_with_triggers.trigger_count(), 0); - } - - #[tokio::test] - async fn test_trigger_filter_every_block() { - let account1: String = "account1".into(); - - let adapter = TriggersAdapter {}; - - let logger = Logger::root(slog::Discard, o!()); - let block1 = new_success_block(1, &account1); - - let filter = TriggerFilter { - block_filter: crate::adapter::NearBlockFilter { - trigger_every_block: true, - }, - ..Default::default() - }; - - let block_with_triggers: BlockWithTriggers = adapter - .triggers_in_block(&logger, block1, &filter) - .await - .expect("failed to execute triggers_in_block"); - assert_eq!(block_with_triggers.trigger_count(), 1); - - let height: Vec = heights_from_triggers(&block_with_triggers); - assert_eq!(height, vec![1]); - } - - #[tokio::test] - async fn test_trigger_filter_every_receipt() { - let account1: String = "account1".into(); - - let adapter = TriggersAdapter {}; - - let logger = Logger::root(slog::Discard, o!()); - let block1 = new_success_block(1, &account1); - - let filter = TriggerFilter { - receipt_filter: NearReceiptFilter { - accounts: HashSet::from_iter(vec![account1]), - }, - ..Default::default() - }; - - let block_with_triggers: BlockWithTriggers = adapter - .triggers_in_block(&logger, block1, &filter) - .await - .expect("failed to execute triggers_in_block"); - assert_eq!(block_with_triggers.trigger_count(), 1); - - let height: Vec = heights_from_triggers(&block_with_triggers); - assert_eq!(height.len(), 0); - } - - fn heights_from_triggers(block: &BlockWithTriggers) -> Vec { - block - .trigger_data - .clone() - .into_iter() - .filter_map(|x| match x { - crate::trigger::NearTrigger::Block(b) => b.header.clone().map(|x| x.height), - _ => None, - }) - .collect() - } - - fn new_success_block(height: u64, receiver_id: &String) -> codec::Block { - codec::Block { - header: Some(BlockHeader { - height, - ..Default::default() - }), - shards: vec![IndexerShard { - receipt_execution_outcomes: vec![IndexerExecutionOutcomeWithReceipt { - receipt: Some(crate::codec::Receipt { - receipt: Some(receipt::Receipt::Action(ReceiptAction { - output_data_receivers: vec![DataReceiver { - receiver_id: receiver_id.clone(), - ..Default::default() - }], - ..Default::default() - })), - receiver_id: receiver_id.clone(), - ..Default::default() - }), - execution_outcome: Some(ExecutionOutcomeWithId { - outcome: Some(ExecutionOutcome { - status: Some(execution_outcome::Status::SuccessValue( - SuccessValueExecutionStatus::default(), - )), - - ..Default::default() - }), - ..Default::default() - }), - }], - ..Default::default() - }], - ..Default::default() - } + Ok(block.ptr()) } } diff --git a/chain/arweave/src/codec.rs b/chain/arweave/src/codec.rs index cfc26b20b0c..df90e83faf8 100644 --- a/chain/arweave/src/codec.rs +++ b/chain/arweave/src/codec.rs @@ -1,109 +1,30 @@ -#[path = "protobuf/sf.near.codec.v1.rs"] +#[path = "protobuf/sf.arweave.r#type.v1.rs"] mod pbcodec; -use graph::{ - blockchain::Block as BlockchainBlock, - blockchain::BlockPtr, - prelude::{hex, web3::types::H256, BlockNumber}, -}; -use std::convert::TryFrom; -use std::fmt::LowerHex; +use graph::{blockchain::Block as BlockchainBlock, blockchain::BlockPtr, prelude::BlockNumber}; pub use pbcodec::*; -impl From<&CryptoHash> for H256 { - fn from(input: &CryptoHash) -> Self { - H256::from_slice(&input.bytes) - } -} - -impl LowerHex for &CryptoHash { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&hex::encode(&self.bytes)) - } -} - -impl BlockHeader { - pub fn parent_ptr(&self) -> Option { - match (self.prev_hash.as_ref(), self.prev_height) { - (Some(hash), number) => Some(BlockPtr::from((H256::from(hash), number))), - _ => None, - } - } -} - -impl<'a> From<&'a BlockHeader> for BlockPtr { - fn from(b: &'a BlockHeader) -> BlockPtr { - BlockPtr::from((H256::from(b.hash.as_ref().unwrap()), b.height)) - } -} - -impl Block { - pub fn header(&self) -> &BlockHeader { - self.header.as_ref().unwrap() - } - - pub fn ptr(&self) -> BlockPtr { - BlockPtr::from(self.header()) - } - - pub fn parent_ptr(&self) -> Option { - self.header().parent_ptr() - } -} - -impl<'a> From<&'a Block> for BlockPtr { - fn from(b: &'a Block) -> BlockPtr { - BlockPtr::from(b.header()) - } -} - impl BlockchainBlock for Block { fn number(&self) -> i32 { - BlockNumber::try_from(self.header().height).unwrap() - } - - fn ptr(&self) -> BlockPtr { - self.into() - } - - fn parent_ptr(&self) -> Option { - self.parent_ptr() - } -} - -impl HeaderOnlyBlock { - pub fn header(&self) -> &BlockHeader { - self.header.as_ref().unwrap() - } -} - -impl<'a> From<&'a HeaderOnlyBlock> for BlockPtr { - fn from(b: &'a HeaderOnlyBlock) -> BlockPtr { - BlockPtr::from(b.header()) - } -} - -impl BlockchainBlock for HeaderOnlyBlock { - fn number(&self) -> i32 { - BlockNumber::try_from(self.header().height).unwrap() + BlockNumber::try_from(self.height).unwrap() } fn ptr(&self) -> BlockPtr { - self.into() + BlockPtr { + hash: self.indep_hash.clone().into(), + number: self.number(), + } } fn parent_ptr(&self) -> Option { - self.header().parent_ptr() - } -} - -impl execution_outcome::Status { - pub fn is_success(&self) -> bool { - use execution_outcome::Status::*; - match self { - Unknown(_) | Failure(_) => false, - SuccessValue(_) | SuccessReceiptId(_) => true, + if self.height == 0 { + return None; } + + Some(BlockPtr { + hash: self.previous_block.clone().into(), + number: self.number().saturating_sub(1), + }) } } diff --git a/chain/arweave/src/data_source.rs b/chain/arweave/src/data_source.rs index c0ae002c38c..a12fa26e53d 100644 --- a/chain/arweave/src/data_source.rs +++ b/chain/arweave/src/data_source.rs @@ -15,9 +15,9 @@ use std::collections::BTreeMap; use std::{convert::TryFrom, sync::Arc}; use crate::chain::Chain; -use crate::trigger::NearTrigger; +use crate::trigger::ArweaveTrigger; -pub const NEAR_KIND: &str = "near"; +pub const ARWEAVE_KIND: &str = "arweave"; /// Runtime representation of a data source. #[derive(Clone, Debug)] @@ -52,23 +52,10 @@ impl blockchain::DataSource for DataSource { let handler = match trigger { // A block trigger matches if a block handler is present. - NearTrigger::Block(_) => match self.handler_for_block() { + ArweaveTrigger::Block(_) => match self.handler_for_block() { Some(handler) => &handler.handler, None => return Ok(None), }, - - // A receipt trigger matches if the receiver matches `source.account` and a receipt - // handler is present. - NearTrigger::Receipt(receipt) => { - if Some(&receipt.receipt.receiver_id) != self.source.account.as_ref() { - return Ok(None); - } - - match self.handler_for_receipt() { - Some(handler) => &handler.handler, - None => return Ok(None), - } - } }; Ok(Some(TriggerWithHandler::new( @@ -123,7 +110,7 @@ impl blockchain::DataSource for DataSource { } fn as_stored_dynamic_data_source(&self) -> StoredDynamicDataSource { - // FIXME (NEAR): Implement me! + // FIXME (ARWEAVE): Implement me! todo!() } @@ -131,17 +118,17 @@ impl blockchain::DataSource for DataSource { _templates: &BTreeMap<&str, &DataSourceTemplate>, _stored: StoredDynamicDataSource, ) -> Result { - // FIXME (NEAR): Implement me correctly + // FIXME (ARWEAVE): Implement me correctly todo!() } fn validate(&self) -> Vec { let mut errors = Vec::new(); - if self.kind != NEAR_KIND { + if self.kind != ARWEAVE_KIND { errors.push(anyhow!( "data source has invalid `kind`, expected {} but found {}", - NEAR_KIND, + ARWEAVE_KIND, self.kind )) } @@ -199,10 +186,6 @@ impl DataSource { fn handler_for_block(&self) -> Option<&MappingBlockHandler> { self.mapping.block_handlers.first() } - - fn handler_for_receipt(&self) -> Option<&ReceiptHandler> { - self.mapping.receipt_handlers.first() - } } #[derive(Clone, Debug, Eq, PartialEq, Deserialize)] @@ -239,42 +222,14 @@ impl blockchain::UnresolvedDataSource for UnresolvedDataSource { } } +/// # TODO +/// +/// add templates for arweave subgraphs impl TryFrom> for DataSource { type Error = Error; fn try_from(_info: DataSourceTemplateInfo) -> Result { - Err(anyhow!("Near subgraphs do not support templates")) - - // How this might be implemented if/when Near gets support for templates: - // let DataSourceTemplateInfo { - // template, - // params, - // context, - // creation_block, - // } = info; - - // let account = params - // .get(0) - // .with_context(|| { - // format!( - // "Failed to create data source from template `{}`: account parameter is missing", - // template.name - // ) - // })? - // .clone(); - - // Ok(DataSource { - // kind: template.kind, - // network: template.network, - // name: template.name, - // source: Source { - // account, - // start_block: 0, - // }, - // mapping: template.mapping, - // context: Arc::new(context), - // creation_block: Some(creation_block), - // }) + Err(anyhow!("Arweave subgraphs do not support templates")) } } diff --git a/chain/arweave/src/lib.rs b/chain/arweave/src/lib.rs index 9b1ddab5ce2..a497e77bf9d 100644 --- a/chain/arweave/src/lib.rs +++ b/chain/arweave/src/lib.rs @@ -8,4 +8,3 @@ mod trigger; pub use crate::chain::Chain; pub use codec::Block; -pub use codec::HeaderOnlyBlock; diff --git a/chain/arweave/src/runtime/abi.rs b/chain/arweave/src/runtime/abi.rs index 703fc126093..a31aac8af86 100644 --- a/chain/arweave/src/runtime/abi.rs +++ b/chain/arweave/src/runtime/abi.rs @@ -1,9 +1,7 @@ use crate::codec; -use crate::trigger::ReceiptWithOutcome; -use graph::anyhow::anyhow; use graph::runtime::gas::GasCounter; use graph::runtime::{asc_new, AscHeap, AscPtr, DeterministicHostError, ToAscObj}; -use graph_runtime_wasm::asc_abi::class::{Array, AscEnum, EnumPayload, Uint8Array}; +use graph_runtime_wasm::asc_abi::class::Array; pub(crate) use super::generated::*; @@ -89,6 +87,7 @@ impl ToAscObj for codec::Block { hash: asc_new(heap, self.hash.as_slice(), gas)?, tx_root: self .tx_root + .as_ref() .map(|tx_root| asc_new(heap, tx_root.as_slice(), gas)) .unwrap_or(Ok(AscPtr::null()))?, wallet_list: asc_new(heap, self.wallet_list.as_slice(), gas)?, @@ -99,10 +98,12 @@ impl ToAscObj for codec::Block { block_size: asc_new(heap, &self.block_size, gas)?, cumulative_diff: self .cumulative_diff + .as_ref() .map(|cumulative_diff| asc_new(heap, &cumulative_diff, gas)) .unwrap_or(Ok(AscPtr::null()))?, hash_list_merkle: self .hash_list_merkle + .as_ref() .map(|hash_list_merkle| asc_new(heap, hash_list_merkle.as_slice(), gas)) .unwrap_or(Ok(AscPtr::null()))?, poa: self diff --git a/chain/arweave/src/runtime/generated.rs b/chain/arweave/src/runtime/generated.rs index ce4ce788b59..4bb64fa2da6 100644 --- a/chain/arweave/src/runtime/generated.rs +++ b/chain/arweave/src/runtime/generated.rs @@ -1,9 +1,7 @@ -use graph::runtime::{ - AscIndexId, AscPtr, AscType, AscValue, DeterministicHostError, IndexForAscTypeId, -}; +use graph::runtime::{AscIndexId, AscPtr, AscType, DeterministicHostError, IndexForAscTypeId}; use graph::semver::Version; use graph_runtime_derive::AscType; -use graph_runtime_wasm::asc_abi::class::{Array, AscEnum, AscString, Uint8Array}; +use graph_runtime_wasm::asc_abi::class::{Array, AscString, Uint8Array}; #[repr(C)] #[derive(AscType)] diff --git a/chain/arweave/src/trigger.rs b/chain/arweave/src/trigger.rs index 747fdf1503a..a9a2553d9eb 100644 --- a/chain/arweave/src/trigger.rs +++ b/chain/arweave/src/trigger.rs @@ -2,7 +2,6 @@ use graph::blockchain; use graph::blockchain::Block; use graph::blockchain::TriggerData; use graph::cheap_clone::CheapClone; -use graph::prelude::hex; use graph::prelude::web3::types::H256; use graph::prelude::BlockNumber; use graph::runtime::asc_new; @@ -15,484 +14,91 @@ use std::{cmp::Ordering, sync::Arc}; use crate::codec; // Logging the block is too verbose, so this strips the block from the trigger for Debug. -impl std::fmt::Debug for NearTrigger { +impl std::fmt::Debug for ArweaveTrigger { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { #[derive(Debug)] - pub enum MappingTriggerWithoutBlock<'a> { + pub enum MappingTriggerWithoutBlock { Block, - - Receipt { - outcome: &'a codec::ExecutionOutcomeWithId, - receipt: &'a codec::Receipt, - }, } let trigger_without_block = match self { - NearTrigger::Block(_) => MappingTriggerWithoutBlock::Block, - NearTrigger::Receipt(receipt) => MappingTriggerWithoutBlock::Receipt { - outcome: &receipt.outcome, - receipt: &receipt.receipt, - }, + ArweaveTrigger::Block(_) => MappingTriggerWithoutBlock::Block, }; write!(f, "{:?}", trigger_without_block) } } -impl blockchain::MappingTrigger for NearTrigger { +impl blockchain::MappingTrigger for ArweaveTrigger { fn to_asc_ptr( self, heap: &mut H, gas: &GasCounter, ) -> Result, DeterministicHostError> { Ok(match self { - NearTrigger::Block(block) => asc_new(heap, block.as_ref(), gas)?.erase(), - NearTrigger::Receipt(receipt) => asc_new(heap, receipt.as_ref(), gas)?.erase(), + ArweaveTrigger::Block(block) => asc_new(heap, block.as_ref(), gas)?.erase(), }) } } #[derive(Clone)] -pub enum NearTrigger { +pub enum ArweaveTrigger { Block(Arc), - Receipt(Arc), } -impl CheapClone for NearTrigger { - fn cheap_clone(&self) -> NearTrigger { +impl CheapClone for ArweaveTrigger { + fn cheap_clone(&self) -> ArweaveTrigger { match self { - NearTrigger::Block(block) => NearTrigger::Block(block.cheap_clone()), - NearTrigger::Receipt(receipt) => NearTrigger::Receipt(receipt.cheap_clone()), + ArweaveTrigger::Block(block) => ArweaveTrigger::Block(block.cheap_clone()), } } } -impl PartialEq for NearTrigger { +impl PartialEq for ArweaveTrigger { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Block(a_ptr), Self::Block(b_ptr)) => a_ptr == b_ptr, - (Self::Receipt(a), Self::Receipt(b)) => a.receipt.receipt_id == b.receipt.receipt_id, - - (Self::Block(_), Self::Receipt(_)) | (Self::Receipt(_), Self::Block(_)) => false, } } } -impl Eq for NearTrigger {} +impl Eq for ArweaveTrigger {} -impl NearTrigger { +impl ArweaveTrigger { pub fn block_number(&self) -> BlockNumber { match self { - NearTrigger::Block(block) => block.number(), - NearTrigger::Receipt(receipt) => receipt.block.number(), + ArweaveTrigger::Block(block) => block.number(), } } pub fn block_hash(&self) -> H256 { match self { - NearTrigger::Block(block) => block.ptr().hash_as_h256(), - NearTrigger::Receipt(receipt) => receipt.block.ptr().hash_as_h256(), + ArweaveTrigger::Block(block) => block.ptr().hash_as_h256(), } } } -impl Ord for NearTrigger { +impl Ord for ArweaveTrigger { fn cmp(&self, other: &Self) -> Ordering { match (self, other) { // Keep the order when comparing two block triggers (Self::Block(..), Self::Block(..)) => Ordering::Equal, - - // Block triggers always come last - (Self::Block(..), _) => Ordering::Greater, - (_, Self::Block(..)) => Ordering::Less, - - // Execution outcomes have no intrinsic ordering information, so we keep the order in - // which they are included in the `receipt_execution_outcomes` field of `IndexerShard`. - (Self::Receipt(..), Self::Receipt(..)) => Ordering::Equal, } } } -impl PartialOrd for NearTrigger { +impl PartialOrd for ArweaveTrigger { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl TriggerData for NearTrigger { +impl TriggerData for ArweaveTrigger { fn error_context(&self) -> std::string::String { match self { - NearTrigger::Block(..) => { + ArweaveTrigger::Block(..) => { format!("Block #{} ({})", self.block_number(), self.block_hash()) } - NearTrigger::Receipt(receipt) => { - format!( - "receipt id {}, block #{} ({})", - hex::encode(&receipt.receipt.receipt_id.as_ref().unwrap().bytes), - self.block_number(), - self.block_hash() - ) - } - } - } -} - -pub struct ReceiptWithOutcome { - // REVIEW: Do we want to actually also have those two below behind an `Arc` wrapper? - pub outcome: codec::ExecutionOutcomeWithId, - pub receipt: codec::Receipt, - pub block: Arc, -} - -#[cfg(test)] -mod tests { - use std::convert::TryFrom; - - use super::*; - - use graph::{ - anyhow::anyhow, - data::subgraph::API_VERSION_0_0_5, - prelude::{hex, BigInt}, - runtime::gas::GasCounter, - }; - - #[test] - fn block_trigger_to_asc_ptr() { - let mut heap = BytesHeap::new(API_VERSION_0_0_5); - let trigger = NearTrigger::Block(Arc::new(block())); - - let result = - blockchain::MappingTrigger::to_asc_ptr(trigger, &mut heap, &GasCounter::default()); - assert!(result.is_ok()); - } - - #[test] - fn receipt_trigger_to_asc_ptr() { - let mut heap = BytesHeap::new(API_VERSION_0_0_5); - let trigger = NearTrigger::Receipt(Arc::new(ReceiptWithOutcome { - block: Arc::new(block()), - outcome: execution_outcome_with_id().unwrap(), - receipt: receipt().unwrap(), - })); - - let result = - blockchain::MappingTrigger::to_asc_ptr(trigger, &mut heap, &GasCounter::default()); - assert!(result.is_ok()); - } - - fn block() -> codec::Block { - codec::Block { - author: "test".to_string(), - header: Some(codec::BlockHeader { - height: 2, - prev_height: 1, - epoch_id: hash("01"), - next_epoch_id: hash("02"), - hash: hash("01"), - prev_hash: hash("00"), - prev_state_root: hash("bb00010203"), - chunk_receipts_root: hash("bb00010203"), - chunk_headers_root: hash("bb00010203"), - chunk_tx_root: hash("bb00010203"), - outcome_root: hash("cc00010203"), - chunks_included: 1, - challenges_root: hash("aa"), - timestamp: 100, - timestamp_nanosec: 0, - random_value: hash("010203"), - validator_proposals: vec![], - chunk_mask: vec![], - gas_price: big_int(10), - block_ordinal: 0, - total_supply: big_int(1_000), - challenges_result: vec![], - last_final_block: hash("00"), - last_final_block_height: 0, - last_ds_final_block: hash("00"), - last_ds_final_block_height: 0, - next_bp_hash: hash("bb"), - block_merkle_root: hash("aa"), - epoch_sync_data_hash: vec![0x00, 0x01], - approvals: vec![], - signature: signature("00"), - latest_protocol_version: 0, - }), - chunk_headers: vec![chunk_header().unwrap()], - shards: vec![codec::IndexerShard { - shard_id: 0, - chunk: Some(codec::IndexerChunk { - author: "near".to_string(), - header: chunk_header(), - transactions: vec![codec::IndexerTransactionWithOutcome { - transaction: Some(codec::SignedTransaction { - signer_id: "signer".to_string(), - public_key: public_key("aabb"), - nonce: 1, - receiver_id: "receiver".to_string(), - actions: vec![], - signature: signature("ff"), - hash: hash("bb"), - }), - outcome: Some(codec::IndexerExecutionOutcomeWithOptionalReceipt { - execution_outcome: execution_outcome_with_id(), - receipt: receipt(), - }), - }], - receipts: vec![receipt().unwrap()], - }), - receipt_execution_outcomes: vec![codec::IndexerExecutionOutcomeWithReceipt { - execution_outcome: execution_outcome_with_id(), - receipt: receipt(), - }], - }], - state_changes: vec![], - } - } - - fn receipt() -> Option { - Some(codec::Receipt { - predecessor_id: "genesis.near".to_string(), - receiver_id: "near".to_string(), - receipt_id: hash("dead"), - receipt: Some(codec::receipt::Receipt::Action(codec::ReceiptAction { - signer_id: "near".to_string(), - signer_public_key: public_key("aa"), - gas_price: big_int(2), - output_data_receivers: vec![], - input_data_ids: vec![], - actions: vec![ - codec::Action { - action: Some(codec::action::Action::CreateAccount( - codec::CreateAccountAction {}, - )), - }, - codec::Action { - action: Some(codec::action::Action::DeployContract( - codec::DeployContractAction { - code: vec![0x01, 0x02], - }, - )), - }, - codec::Action { - action: Some(codec::action::Action::FunctionCall( - codec::FunctionCallAction { - method_name: "func".to_string(), - args: vec![0x01, 0x02], - gas: 1000, - deposit: big_int(100), - }, - )), - }, - codec::Action { - action: Some(codec::action::Action::Transfer(codec::TransferAction { - deposit: big_int(100), - })), - }, - codec::Action { - action: Some(codec::action::Action::Stake(codec::StakeAction { - stake: big_int(100), - public_key: public_key("aa"), - })), - }, - codec::Action { - action: Some(codec::action::Action::AddKey(codec::AddKeyAction { - public_key: public_key("aa"), - access_key: Some(codec::AccessKey { - nonce: 1, - permission: Some(codec::AccessKeyPermission { - permission: Some( - codec::access_key_permission::Permission::FunctionCall( - codec::FunctionCallPermission { - // allowance can be None, so let's test this out here - allowance: None, - receiver_id: "receiver".to_string(), - method_names: vec!["sayGm".to_string()], - }, - ), - ), - }), - }), - })), - }, - codec::Action { - action: Some(codec::action::Action::AddKey(codec::AddKeyAction { - public_key: public_key("aa"), - access_key: Some(codec::AccessKey { - nonce: 1, - permission: Some(codec::AccessKeyPermission { - permission: Some( - codec::access_key_permission::Permission::FullAccess( - codec::FullAccessPermission {}, - ), - ), - }), - }), - })), - }, - codec::Action { - action: Some(codec::action::Action::DeleteKey(codec::DeleteKeyAction { - public_key: public_key("aa"), - })), - }, - codec::Action { - action: Some(codec::action::Action::DeleteAccount( - codec::DeleteAccountAction { - beneficiary_id: "suicided.near".to_string(), - }, - )), - }, - ], - })), - }) - } - - fn chunk_header() -> Option { - Some(codec::ChunkHeader { - chunk_hash: vec![0x00], - prev_block_hash: vec![0x01], - outcome_root: vec![0x02], - prev_state_root: vec![0x03], - encoded_merkle_root: vec![0x04], - encoded_length: 1, - height_created: 2, - height_included: 3, - shard_id: 4, - gas_used: 5, - gas_limit: 6, - validator_reward: big_int(7), - balance_burnt: big_int(7), - outgoing_receipts_root: vec![0x07], - tx_root: vec![0x08], - validator_proposals: vec![codec::ValidatorStake { - account_id: "account".to_string(), - public_key: public_key("aa"), - stake: big_int(10), - }], - signature: signature("ff"), - }) - } - - fn execution_outcome_with_id() -> Option { - Some(codec::ExecutionOutcomeWithId { - proof: Some(codec::MerklePath { path: vec![] }), - block_hash: hash("aa"), - id: hash("beef"), - outcome: execution_outcome(), - }) - } - - fn execution_outcome() -> Option { - Some(codec::ExecutionOutcome { - logs: vec!["string".to_string()], - receipt_ids: vec![], - gas_burnt: 1, - tokens_burnt: big_int(2), - executor_id: "near".to_string(), - metadata: 0, - status: Some(codec::execution_outcome::Status::SuccessValue( - codec::SuccessValueExecutionStatus { value: vec![0x00] }, - )), - }) - } - - fn big_int(input: u64) -> Option { - let value = - BigInt::try_from(input).expect(format!("Invalid BigInt value {}", input).as_ref()); - let bytes = value.to_signed_bytes_le(); - - Some(codec::BigInt { bytes }) - } - - fn hash(input: &str) -> Option { - Some(codec::CryptoHash { - bytes: hex::decode(input).expect(format!("Invalid hash value {}", input).as_ref()), - }) - } - - fn public_key(input: &str) -> Option { - Some(codec::PublicKey { - r#type: 0, - bytes: hex::decode(input).expect(format!("Invalid PublicKey value {}", input).as_ref()), - }) - } - - fn signature(input: &str) -> Option { - Some(codec::Signature { - r#type: 0, - bytes: hex::decode(input).expect(format!("Invalid Signature value {}", input).as_ref()), - }) - } - - struct BytesHeap { - api_version: graph::semver::Version, - memory: Vec, - } - - impl BytesHeap { - fn new(api_version: graph::semver::Version) -> Self { - Self { - api_version, - memory: vec![], - } - } - } - - impl AscHeap for BytesHeap { - fn raw_new( - &mut self, - bytes: &[u8], - _gas: &GasCounter, - ) -> Result { - self.memory.extend_from_slice(bytes); - Ok((self.memory.len() - bytes.len()) as u32) - } - - fn get( - &self, - offset: u32, - size: u32, - _gas: &GasCounter, - ) -> Result, DeterministicHostError> { - let memory_byte_count = self.memory.len(); - if memory_byte_count == 0 { - return Err(DeterministicHostError::from(anyhow!( - "No memory is allocated" - ))); - } - - let start_offset = offset as usize; - let end_offset_exclusive = start_offset + size as usize; - - if start_offset >= memory_byte_count { - return Err(DeterministicHostError::from(anyhow!( - "Start offset {} is outside of allocated memory, max offset is {}", - start_offset, - memory_byte_count - 1 - ))); - } - - if end_offset_exclusive > memory_byte_count { - return Err(DeterministicHostError::from(anyhow!( - "End of offset {} is outside of allocated memory, max offset is {}", - end_offset_exclusive, - memory_byte_count - 1 - ))); - } - - return Ok(Vec::from(&self.memory[start_offset..end_offset_exclusive])); - } - - fn api_version(&self) -> graph::semver::Version { - self.api_version.clone() - } - - fn asc_type_id( - &mut self, - type_id_index: graph::runtime::IndexForAscTypeId, - ) -> Result { - // Not totally clear what is the purpose of this method, why not a default implementation here? - Ok(type_id_index as u32) } } } From 46d5a553fc0f019d8c0be48ed3d11750dfcb4ebe Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Thu, 14 Apr 2022 06:59:13 +0800 Subject: [PATCH 05/19] chore(subgraph): register arweave --- core/Cargo.toml | 1 + core/src/subgraph/instance_manager.rs | 7 +++++++ core/src/subgraph/registrar.rs | 17 +++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/core/Cargo.toml b/core/Cargo.toml index 07ad99c11dd..da7ca277c0b 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -13,6 +13,7 @@ futures = { version="0.3.4", features=["compat"] } graph = { path = "../graph" } # This dependency is temporary. The multiblockchain refactoring is not # finished as long as this dependency exists +graph-chain-arweave = { path = "../chain/arweave" } graph-chain-ethereum = { path = "../chain/ethereum" } graph-chain-near = { path = "../chain/near" } graph-chain-tendermint = { path = "../chain/tendermint" } diff --git a/core/src/subgraph/instance_manager.rs b/core/src/subgraph/instance_manager.rs index 52076494940..57b85ea47dc 100644 --- a/core/src/subgraph/instance_manager.rs +++ b/core/src/subgraph/instance_manager.rs @@ -39,6 +39,13 @@ impl SubgraphInstanceManagerTrait for SubgraphInstanceManager< let subgraph_start_future = async move { match BlockchainKind::from_manifest(&manifest)? { + BlockchainKind::Arweave => { + instance_manager + .start_subgraph_inner::( + logger, loc, manifest, stop_block, + ) + .await + } BlockchainKind::Ethereum => { instance_manager .start_subgraph_inner::( diff --git a/core/src/subgraph/registrar.rs b/core/src/subgraph/registrar.rs index c17b6d000c7..09fc9a6331b 100644 --- a/core/src/subgraph/registrar.rs +++ b/core/src/subgraph/registrar.rs @@ -296,6 +296,23 @@ where })?; match kind { + BlockchainKind::Arweave => { + create_subgraph_version::( + &logger, + self.store.clone(), + self.chains.cheap_clone(), + name.clone(), + hash.cheap_clone(), + start_block, + raw, + node_id, + debug_fork, + self.version_switching_mode, + &self.resolver, + ) + .await? + } + BlockchainKind::Ethereum => { create_subgraph_version::( &logger, From 6fbd820e00a28ea27c52b3fe45920d38b8d85fa9 Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Thu, 14 Apr 2022 06:59:21 +0800 Subject: [PATCH 06/19] chore(index-node): register arweave --- Cargo.lock | 2 ++ server/index-node/Cargo.toml | 1 + server/index-node/src/resolver.rs | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 2974e811c9a..576bfc3219e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1495,6 +1495,7 @@ dependencies = [ "futures 0.1.31", "futures 0.3.16", "graph", + "graph-chain-arweave", "graph-chain-ethereum", "graph-chain-near", "graph-chain-tendermint", @@ -1650,6 +1651,7 @@ dependencies = [ "either", "futures 0.3.16", "graph", + "graph-chain-arweave", "graph-chain-ethereum", "graph-chain-near", "graph-chain-tendermint", diff --git a/server/index-node/Cargo.toml b/server/index-node/Cargo.toml index 70fe604bada..1df356130be 100644 --- a/server/index-node/Cargo.toml +++ b/server/index-node/Cargo.toml @@ -9,6 +9,7 @@ either = "1.6.1" futures = "0.3.4" graph = { path = "../../graph" } graph-graphql = { path = "../../graphql" } +graph-chain-arweave = { path = "../../chain/arweave" } graph-chain-ethereum = { path = "../../chain/ethereum" } graph-chain-near = { path = "../../chain/near" } graph-chain-tendermint = { path = "../../chain/tendermint" } diff --git a/server/index-node/src/resolver.rs b/server/index-node/src/resolver.rs index fdfb0deb2fd..65582e3f132 100644 --- a/server/index-node/src/resolver.rs +++ b/server/index-node/src/resolver.rs @@ -510,6 +510,24 @@ impl IndexNodeResolver { ) .await? } + + BlockchainKind::Arweave => { + let unvalidated_subgraph_manifest = + UnvalidatedSubgraphManifest::::resolve( + deployment_hash, + raw, + &self.link_resolver, + &self.logger, + ENV_VARS.max_spec_version.clone(), + ) + .await?; + + validate_and_extract_features( + &self.store.subgraph_store(), + unvalidated_subgraph_manifest, + ) + .await? + } } }; From 770269dcf5168e699055a27694b2d356968f4d1a Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Thu, 14 Apr 2022 07:21:01 +0800 Subject: [PATCH 07/19] feat(chain): use BigInt instead of number string in Arweave proto --- chain/arweave/proto/type.proto | 29 +++---- chain/arweave/src/codec.rs | 6 ++ .../src/protobuf/sf.arweave.r#type.v1.rs | 53 ++++++------ chain/arweave/src/runtime/abi.rs | 84 ++++++++++++++----- chain/arweave/src/runtime/generated.rs | 18 ++-- 5 files changed, 118 insertions(+), 72 deletions(-) diff --git a/chain/arweave/proto/type.proto b/chain/arweave/proto/type.proto index c15d1c1562e..b3a41a4a56a 100644 --- a/chain/arweave/proto/type.proto +++ b/chain/arweave/proto/type.proto @@ -4,6 +4,10 @@ package sf.arweave.type.v1; option go_package = "github.com/ChainSafe/firehose-arweave/pb/sf/arweave/type/v1;pbcodec"; +message BigInt { + bytes bytes = 1; +} + message Block { // Firehose block version (unrelated to Arweave block version) uint32 ver = 1; @@ -18,13 +22,13 @@ message Block { // POSIX time of the last difficulty retarget uint64 last_retarget = 6; // Mining difficulty; the number `hash` must be greater than. - string diff = 7; + BigInt diff = 7; // How many blocks have passed since the genesis block uint64 height = 8; // Mining solution hash of the block; must satisfy the mining difficulty bytes hash = 9; // Merkle root of the tree of Merkle roots of block's transactions' data. - optional bytes tx_root = 10; + bytes tx_root = 10; // Transactions contained within this block repeated Transaction txs = 11; // The root hash of the Merkle Patricia Tree containing @@ -36,21 +40,18 @@ message Block { // Tags that a block producer can add to a block repeated Tag tags = 14; // Size of reward pool - string reward_pool = 15; + BigInt reward_pool = 15; // Size of the weave in bytes - string weave_size = 16; + BigInt weave_size = 16; // Size of this block in bytes - string block_size = 17; + BigInt block_size = 17; // Required after the version 1.8 fork. Zero otherwise. // The sum of the average number of hashes computed // by the network to produce the past blocks including this one. - optional string cumulative_diff = 18; - // The list of the block identifiers of the last - // STORE_BLOCKS_BEHIND_CURRENT blocks. - repeated bytes hash_list = 19; + BigInt cumulative_diff = 18; // Required after the version 1.8 fork. Null byte otherwise. // The Merkle root of the block index - the list of {`indep_hash`; `weave_size`; `tx_root`} triplets - optional bytes hash_list_merkle = 20; + bytes hash_list_merkle = 20; // The proof of access; Used after v2.4 only; set as defaults otherwise ProofOfAccess poa = 21; } @@ -74,7 +75,7 @@ message Transaction { // 1 or 2 for v1 or v2 transactions. More allowable in the future uint32 format = 1; // The transaction identifier. - string id = 2; + bytes id = 2; // Either the identifier of the previous transaction from the same // wallet or the identifier of one of the last ?MAX_TX_ANCHOR_DEPTH blocks. bytes last_tx = 3; @@ -85,19 +86,19 @@ message Transaction { // The address of the recipient; if any. The SHA2-256 hash of the public key. bytes target = 6; // The amount of Winstons to send to the recipient; if any. - string quantity = 7; + BigInt quantity = 7; // The data to upload; if any. For v2 transactions; the field is optional // - a fee is charged based on the `data_size` field; // data may be uploaded any time later in chunks. bytes data = 8; // Size in bytes of the transaction data. - string data_size = 9; + BigInt data_size = 9; // The Merkle root of the Merkle tree of data chunks. bytes data_root = 10; // The signature. bytes signature = 11; // The fee in Winstons. - string reward = 12; + BigInt reward = 12; } diff --git a/chain/arweave/src/codec.rs b/chain/arweave/src/codec.rs index df90e83faf8..267aad5f9cb 100644 --- a/chain/arweave/src/codec.rs +++ b/chain/arweave/src/codec.rs @@ -28,3 +28,9 @@ impl BlockchainBlock for Block { }) } } + +impl AsRef<[u8]> for BigInt { + fn as_ref(&self) -> &[u8] { + self.bytes.as_ref() + } +} diff --git a/chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs b/chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs index 6ca30a2e9ed..75b85922ae2 100644 --- a/chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs +++ b/chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs @@ -1,4 +1,9 @@ #[derive(Clone, PartialEq, ::prost::Message)] +pub struct BigInt { + #[prost(bytes = "vec", tag = "1")] + pub bytes: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] pub struct Block { /// Firehose block version (unrelated to Arweave block version) #[prost(uint32, tag = "1")] @@ -19,8 +24,8 @@ pub struct Block { #[prost(uint64, tag = "6")] pub last_retarget: u64, /// Mining difficulty; the number `hash` must be greater than. - #[prost(string, tag = "7")] - pub diff: ::prost::alloc::string::String, + #[prost(message, optional, tag = "7")] + pub diff: ::core::option::Option, /// How many blocks have passed since the genesis block #[prost(uint64, tag = "8")] pub height: u64, @@ -28,8 +33,8 @@ pub struct Block { #[prost(bytes = "vec", tag = "9")] pub hash: ::prost::alloc::vec::Vec, /// Merkle root of the tree of Merkle roots of block's transactions' data. - #[prost(bytes = "vec", optional, tag = "10")] - pub tx_root: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", tag = "10")] + pub tx_root: ::prost::alloc::vec::Vec, /// Transactions contained within this block #[prost(message, repeated, tag = "11")] pub txs: ::prost::alloc::vec::Vec, @@ -45,27 +50,23 @@ pub struct Block { #[prost(message, repeated, tag = "14")] pub tags: ::prost::alloc::vec::Vec, /// Size of reward pool - #[prost(string, tag = "15")] - pub reward_pool: ::prost::alloc::string::String, + #[prost(message, optional, tag = "15")] + pub reward_pool: ::core::option::Option, /// Size of the weave in bytes - #[prost(string, tag = "16")] - pub weave_size: ::prost::alloc::string::String, + #[prost(message, optional, tag = "16")] + pub weave_size: ::core::option::Option, /// Size of this block in bytes - #[prost(string, tag = "17")] - pub block_size: ::prost::alloc::string::String, + #[prost(message, optional, tag = "17")] + pub block_size: ::core::option::Option, /// Required after the version 1.8 fork. Zero otherwise. /// The sum of the average number of hashes computed /// by the network to produce the past blocks including this one. - #[prost(string, optional, tag = "18")] - pub cumulative_diff: ::core::option::Option<::prost::alloc::string::String>, - /// The list of the block identifiers of the last - /// STORE_BLOCKS_BEHIND_CURRENT blocks. - #[prost(bytes = "vec", repeated, tag = "19")] - pub hash_list: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + #[prost(message, optional, tag = "18")] + pub cumulative_diff: ::core::option::Option, /// Required after the version 1.8 fork. Null byte otherwise. /// The Merkle root of the block index - the list of {`indep_hash`; `weave_size`; `tx_root`} triplets - #[prost(bytes = "vec", optional, tag = "20")] - pub hash_list_merkle: ::core::option::Option<::prost::alloc::vec::Vec>, + #[prost(bytes = "vec", tag = "20")] + pub hash_list_merkle: ::prost::alloc::vec::Vec, /// The proof of access; Used after v2.4 only; set as defaults otherwise #[prost(message, optional, tag = "21")] pub poa: ::core::option::Option, @@ -95,8 +96,8 @@ pub struct Transaction { #[prost(uint32, tag = "1")] pub format: u32, /// The transaction identifier. - #[prost(string, tag = "2")] - pub id: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub id: ::prost::alloc::vec::Vec, /// Either the identifier of the previous transaction from the same /// wallet or the identifier of one of the last ?MAX_TX_ANCHOR_DEPTH blocks. #[prost(bytes = "vec", tag = "3")] @@ -111,16 +112,16 @@ pub struct Transaction { #[prost(bytes = "vec", tag = "6")] pub target: ::prost::alloc::vec::Vec, /// The amount of Winstons to send to the recipient; if any. - #[prost(string, tag = "7")] - pub quantity: ::prost::alloc::string::String, + #[prost(message, optional, tag = "7")] + pub quantity: ::core::option::Option, /// The data to upload; if any. For v2 transactions; the field is optional /// - a fee is charged based on the `data_size` field; /// data may be uploaded any time later in chunks. #[prost(bytes = "vec", tag = "8")] pub data: ::prost::alloc::vec::Vec, /// Size in bytes of the transaction data. - #[prost(string, tag = "9")] - pub data_size: ::prost::alloc::string::String, + #[prost(message, optional, tag = "9")] + pub data_size: ::core::option::Option, /// The Merkle root of the Merkle tree of data chunks. #[prost(bytes = "vec", tag = "10")] pub data_root: ::prost::alloc::vec::Vec, @@ -128,8 +129,8 @@ pub struct Transaction { #[prost(bytes = "vec", tag = "11")] pub signature: ::prost::alloc::vec::Vec, /// The fee in Winstons. - #[prost(string, tag = "12")] - pub reward: ::prost::alloc::string::String, + #[prost(message, optional, tag = "12")] + pub reward: ::core::option::Option, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct Tag { diff --git a/chain/arweave/src/runtime/abi.rs b/chain/arweave/src/runtime/abi.rs index a31aac8af86..5f05a6c5820 100644 --- a/chain/arweave/src/runtime/abi.rs +++ b/chain/arweave/src/runtime/abi.rs @@ -55,17 +55,35 @@ impl ToAscObj for codec::Transaction { ) -> Result { Ok(AscTransaction { format: self.format, - id: asc_new(heap, &self.id, gas)?, + id: asc_new(heap, self.id.as_slice(), gas)?, last_tx: asc_new(heap, self.last_tx.as_slice(), gas)?, owner: asc_new(heap, self.owner.as_slice(), gas)?, tags: asc_new(heap, &self.tags, gas)?, target: asc_new(heap, self.target.as_slice(), gas)?, - quantity: asc_new(heap, &self.quantity, gas)?, + quantity: asc_new( + heap, + self.quantity + .as_ref() + .map(|b| b.as_ref()) + .unwrap_or_default(), + gas, + )?, data: asc_new(heap, self.data.as_slice(), gas)?, - data_size: asc_new(heap, &self.data_size, gas)?, + data_size: asc_new( + heap, + self.data_size + .as_ref() + .map(|b| b.as_ref()) + .unwrap_or_default(), + gas, + )?, data_root: asc_new(heap, self.data_root.as_slice(), gas)?, signature: asc_new(heap, self.signature.as_slice(), gas)?, - reward: asc_new(heap, &self.reward, gas)?, + reward: asc_new( + heap, + self.reward.as_ref().map(|b| b.as_ref()).unwrap_or_default(), + gas, + )?, }) } } @@ -82,30 +100,50 @@ impl ToAscObj for codec::Block { previous_block: asc_new(heap, self.previous_block.as_slice(), gas)?, timestamp: self.timestamp, last_retarget: self.last_retarget, - diff: asc_new(heap, &self.diff, gas)?, + diff: asc_new( + heap, + self.diff.as_ref().map(|b| b.as_ref()).unwrap_or_default(), + gas, + )?, height: self.height, hash: asc_new(heap, self.hash.as_slice(), gas)?, - tx_root: self - .tx_root - .as_ref() - .map(|tx_root| asc_new(heap, tx_root.as_slice(), gas)) - .unwrap_or(Ok(AscPtr::null()))?, + tx_root: asc_new(heap, self.tx_root.as_slice(), gas)?, wallet_list: asc_new(heap, self.wallet_list.as_slice(), gas)?, reward_addr: asc_new(heap, self.reward_addr.as_slice(), gas)?, tags: asc_new(heap, &self.tags, gas)?, - reward_pool: asc_new(heap, &self.reward_pool, gas)?, - weave_size: asc_new(heap, &self.weave_size, gas)?, - block_size: asc_new(heap, &self.block_size, gas)?, - cumulative_diff: self - .cumulative_diff - .as_ref() - .map(|cumulative_diff| asc_new(heap, &cumulative_diff, gas)) - .unwrap_or(Ok(AscPtr::null()))?, - hash_list_merkle: self - .hash_list_merkle - .as_ref() - .map(|hash_list_merkle| asc_new(heap, hash_list_merkle.as_slice(), gas)) - .unwrap_or(Ok(AscPtr::null()))?, + reward_pool: asc_new( + heap, + self.reward_pool + .as_ref() + .map(|b| b.as_ref()) + .unwrap_or_default(), + gas, + )?, + weave_size: asc_new( + heap, + self.weave_size + .as_ref() + .map(|b| b.as_ref()) + .unwrap_or_default(), + gas, + )?, + block_size: asc_new( + heap, + self.block_size + .as_ref() + .map(|b| b.as_ref()) + .unwrap_or_default(), + gas, + )?, + cumulative_diff: asc_new( + heap, + self.cumulative_diff + .as_ref() + .map(|b| b.as_ref()) + .unwrap_or_default(), + gas, + )?, + hash_list_merkle: asc_new(heap, self.hash_list_merkle.as_slice(), gas)?, poa: self .poa .as_ref() diff --git a/chain/arweave/src/runtime/generated.rs b/chain/arweave/src/runtime/generated.rs index 4bb64fa2da6..26536defc82 100644 --- a/chain/arweave/src/runtime/generated.rs +++ b/chain/arweave/src/runtime/generated.rs @@ -11,17 +11,17 @@ pub struct AscBlock { pub previous_block: AscPtr, pub timestamp: u64, pub last_retarget: u64, - pub diff: AscPtr, + pub diff: AscPtr, pub height: u64, pub hash: AscPtr, pub tx_root: AscPtr, pub wallet_list: AscPtr, pub reward_addr: AscPtr, pub tags: AscPtr, - pub reward_pool: AscPtr, - pub weave_size: AscPtr, - pub block_size: AscPtr, - pub cumulative_diff: AscPtr, + pub reward_pool: AscPtr, + pub weave_size: AscPtr, + pub block_size: AscPtr, + pub cumulative_diff: AscPtr, pub hash_list_merkle: AscPtr, pub poa: AscPtr, } @@ -47,17 +47,17 @@ impl AscIndexId for AscProofOfAccess { #[derive(AscType)] pub struct AscTransaction { pub format: u32, - pub id: AscPtr, + pub id: AscPtr, pub last_tx: AscPtr, pub owner: AscPtr, pub tags: AscPtr, pub target: AscPtr, - pub quantity: AscPtr, + pub quantity: AscPtr, pub data: AscPtr, - pub data_size: AscPtr, + pub data_size: AscPtr, pub data_root: AscPtr, pub signature: AscPtr, - pub reward: AscPtr, + pub reward: AscPtr, } impl AscIndexId for AscTransaction { From ef16c8ef99324847aec26eb2ff2beccd3d58e48c Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Mon, 18 Apr 2022 00:59:16 +0800 Subject: [PATCH 08/19] chore(node): register arweave --- node/src/main.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/node/src/main.rs b/node/src/main.rs index 191758acf02..a4c820eaa94 100644 --- a/node/src/main.rs +++ b/node/src/main.rs @@ -10,6 +10,7 @@ use graph::log::logger; use graph::prelude::{IndexNodeServer as _, JsonRpcServer as _, *}; use graph::prometheus::Registry; use graph::url::Url; +use graph_chain_arweave::{self as arweave, Block as ArweaveBlock}; use graph_chain_ethereum as ethereum; use graph_chain_near::{self as near, HeaderOnlyBlock as NearFirehoseHeaderOnlyBlock}; use graph_chain_tendermint::{self as tendermint, EventList as TendermintFirehoseEventList}; @@ -239,6 +240,14 @@ async fn main() { // `blockchain_map`. let mut blockchain_map = BlockchainMap::new(); + let (arweave_networks, arweave_idents) = connect_firehose_networks::( + &logger, + firehose_networks_by_kind + .remove(&BlockchainKind::Arweave) + .unwrap_or_else(|| FirehoseNetworks::new()), + ) + .await; + let (eth_networks, ethereum_idents) = connect_ethereum_networks(&logger, eth_networks).await; @@ -262,12 +271,22 @@ async fn main() { let network_identifiers = ethereum_idents .into_iter() + .chain(arweave_idents) .chain(near_idents) .chain(tendermint_idents) .collect(); let network_store = store_builder.network_store(network_identifiers); + let arweave_chains = arweave_networks_as_chains( + &mut blockchain_map, + &logger, + &arweave_networks, + network_store.as_ref(), + &logger_factory, + metrics_registry.clone(), + ); + let ethereum_chains = ethereum_networks_as_chains( &mut blockchain_map, &logger, @@ -341,11 +360,18 @@ async fn main() { ); } + start_firehose_block_ingestor::<_, ArweaveBlock>( + &logger, + &network_store, + arweave_chains, + ); + start_firehose_block_ingestor::<_, NearFirehoseHeaderOnlyBlock>( &logger, &network_store, near_chains, ); + start_firehose_block_ingestor::<_, TendermintFirehoseEventList>( &logger, &network_store, @@ -529,6 +555,55 @@ async fn main() { futures::future::pending::<()>().await; } +/// Return the hashmap of NEAR chains and also add them to `blockchain_map`. +fn arweave_networks_as_chains( + blockchain_map: &mut BlockchainMap, + logger: &Logger, + firehose_networks: &FirehoseNetworks, + store: &Store, + logger_factory: &LoggerFactory, + metrics_registry: Arc, +) -> HashMap> { + let chains: Vec<_> = firehose_networks + .networks + .iter() + .filter_map(|(chain_id, endpoints)| { + store + .block_store() + .chain_store(chain_id) + .map(|chain_store| (chain_id, chain_store, endpoints)) + .or_else(|| { + error!( + logger, + "No store configured for NEAR chain {}; ignoring this chain", chain_id + ); + None + }) + }) + .map(|(chain_id, chain_store, endpoints)| { + ( + chain_id.clone(), + FirehoseChain { + chain: Arc::new(arweave::Chain::new( + logger_factory.clone(), + chain_id.clone(), + chain_store, + endpoints.clone(), + metrics_registry.clone(), + )), + firehose_endpoints: endpoints.clone(), + }, + ) + }) + .collect(); + + for (chain_id, firehose_chain) in chains.iter() { + blockchain_map.insert::(chain_id.clone(), firehose_chain.chain.clone()) + } + + HashMap::from_iter(chains) +} + /// Return the hashmap of ethereum chains and also add them to `blockchain_map`. fn ethereum_networks_as_chains( blockchain_map: &mut BlockchainMap, From db0c53382630d1d99150061af4a6cfba03f5701c Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Thu, 21 Apr 2022 01:37:00 +0800 Subject: [PATCH 09/19] feat(chain): add TransactionArray in arweave abi --- chain/arweave/src/chain.rs | 2 +- chain/arweave/src/runtime/abi.rs | 16 +++++++++++++ chain/arweave/src/runtime/generated.rs | 31 ++++++++++++++++++++++---- graph/src/runtime/mod.rs | 5 +++-- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/chain/arweave/src/chain.rs b/chain/arweave/src/chain.rs index c2cbe7bf235..0d8001fab96 100644 --- a/chain/arweave/src/chain.rs +++ b/chain/arweave/src/chain.rs @@ -230,7 +230,7 @@ impl TriggersAdapterTrait for TriggersAdapter { async fn parent_ptr(&self, block: &BlockPtr) -> Result, Error> { // FIXME (ARWEAVE): Might not be necessary for ARWEAVE support for now Ok(Some(BlockPtr { - hash: BlockHash::from(vec![0xff; 32]), + hash: BlockHash::from(vec![0xff; 48]), number: block.number.saturating_sub(1), })) } diff --git a/chain/arweave/src/runtime/abi.rs b/chain/arweave/src/runtime/abi.rs index 5f05a6c5820..069f1706298 100644 --- a/chain/arweave/src/runtime/abi.rs +++ b/chain/arweave/src/runtime/abi.rs @@ -18,6 +18,20 @@ impl ToAscObj for codec::Tag { } } +impl ToAscObj for Vec { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + let content = self + .iter() + .map(|x| asc_new(heap, x, gas)) + .collect::, _>>()?; + Ok(AscTransactionArray(Array::new(&*content, heap, gas)?)) + } +} + impl ToAscObj for Vec { fn to_asc_obj( &self, @@ -95,6 +109,7 @@ impl ToAscObj for codec::Block { gas: &GasCounter, ) -> Result { Ok(AscBlock { + // ver: self.ver, indep_hash: asc_new(heap, self.indep_hash.as_slice(), gas)?, nonce: asc_new(heap, self.nonce.as_slice(), gas)?, previous_block: asc_new(heap, self.previous_block.as_slice(), gas)?, @@ -108,6 +123,7 @@ impl ToAscObj for codec::Block { height: self.height, hash: asc_new(heap, self.hash.as_slice(), gas)?, tx_root: asc_new(heap, self.tx_root.as_slice(), gas)?, + txs: asc_new(heap, &self.txs, gas)?, wallet_list: asc_new(heap, self.wallet_list.as_slice(), gas)?, reward_addr: asc_new(heap, self.reward_addr.as_slice(), gas)?, tags: asc_new(heap, &self.tags, gas)?, diff --git a/chain/arweave/src/runtime/generated.rs b/chain/arweave/src/runtime/generated.rs index 26536defc82..c14074de358 100644 --- a/chain/arweave/src/runtime/generated.rs +++ b/chain/arweave/src/runtime/generated.rs @@ -4,17 +4,19 @@ use graph_runtime_derive::AscType; use graph_runtime_wasm::asc_abi::class::{Array, AscString, Uint8Array}; #[repr(C)] -#[derive(AscType)] +#[derive(AscType, Default)] pub struct AscBlock { + // pub ver: u32, + pub timestamp: u64, + pub last_retarget: u64, + pub height: u64, pub indep_hash: AscPtr, pub nonce: AscPtr, pub previous_block: AscPtr, - pub timestamp: u64, - pub last_retarget: u64, pub diff: AscPtr, - pub height: u64, pub hash: AscPtr, pub tx_root: AscPtr, + pub txs: AscPtr, pub wallet_list: AscPtr, pub reward_addr: AscPtr, pub tags: AscPtr, @@ -75,6 +77,27 @@ impl AscIndexId for AscTag { const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::ArweaveTag; } +#[repr(C)] +pub struct AscTransactionArray(pub(crate) Array>); + +impl AscType for AscTransactionArray { + fn to_asc_bytes(&self) -> Result, DeterministicHostError> { + self.0.to_asc_bytes() + } + + fn from_asc_bytes( + asc_obj: &[u8], + api_version: &Version, + ) -> Result { + Ok(Self(Array::from_asc_bytes(asc_obj, api_version)?)) + } +} + +impl AscIndexId for AscTransactionArray { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::ArweaveTransactionArray; +} + +#[repr(C)] pub struct AscTagArray(pub(crate) Array>); impl AscType for AscTagArray { diff --git a/graph/src/runtime/mod.rs b/graph/src/runtime/mod.rs index 5a8e45bfe45..7217453aa1e 100644 --- a/graph/src/runtime/mod.rs +++ b/graph/src/runtime/mod.rs @@ -324,8 +324,9 @@ pub enum IndexForAscTypeId { ArweaveBlock = 2500, ArweaveProofOfAccess = 2501, ArweaveTransaction = 2502, - ArweaveTag = 2503, - ArweaveTagArray = 2504, + ArweaveTransactionArray = 2503, + ArweaveTag = 2504, + ArweaveTagArray = 2505, // Continue to add more Tendermint type IDs here. // e.g.: // NextArweaveType = 2505, From fedccc88e482e99cbf6deb5df0fe0f50a746dfce Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Thu, 21 Apr 2022 01:42:53 +0800 Subject: [PATCH 10/19] workaround(blockchain)!: hack the block hash of arweave --- graph/src/blockchain/types.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/graph/src/blockchain/types.rs b/graph/src/blockchain/types.rs index c1b1f7e7495..fe9852cf093 100644 --- a/graph/src/blockchain/types.rs +++ b/graph/src/blockchain/types.rs @@ -104,8 +104,11 @@ impl BlockPtr { self.number } + // FIXME: + // + // workaround for arweave pub fn hash_as_h256(&self) -> H256 { - H256::from_slice(self.hash_slice()) + H256::from_slice(&self.hash_slice()[0..32]) } pub fn hash_slice(&self) -> &[u8] { From ebf29b15c271b3c6a867f8eae3e95a3c215b94a8 Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Thu, 21 Apr 2022 19:56:42 +0800 Subject: [PATCH 11/19] workaround(store)!: hack the block hash of arweave --- store/postgres/src/chain_store.rs | 10 +++++++--- store/postgres/src/deployment.rs | 2 +- store/postgres/src/detail.rs | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/store/postgres/src/chain_store.rs b/store/postgres/src/chain_store.rs index e6a09f2efcb..475dca92a94 100644 --- a/store/postgres/src/chain_store.rs +++ b/store/postgres/src/chain_store.rs @@ -1444,9 +1444,13 @@ impl ChainStoreTrait for ChainStore { .map(|rows| { rows.first() .map(|(hash_opt, number_opt)| match (hash_opt, number_opt) { - (Some(hash), Some(number)) => { - Some((hash.parse().unwrap(), *number).into()) - } + (Some(hash), Some(number)) => Some( + ( + H256::from_slice(&hex::decode(hash).unwrap()[0..32]), + *number, + ) + .into(), + ), (None, None) => None, _ => unreachable!(), }) diff --git a/store/postgres/src/deployment.rs b/store/postgres/src/deployment.rs index 620ba91dfd6..2536100872c 100644 --- a/store/postgres/src/deployment.rs +++ b/store/postgres/src/deployment.rs @@ -158,7 +158,7 @@ fn graft( match graft { (None, None, None) => Ok(None), (Some(subgraph), Some(hash), Some(block)) => { - let hash = H256::from_slice(hash.as_slice()); + let hash = H256::from_slice(&hash.as_slice()[0..32]); let block = block.to_u64().expect("block numbers fit into a u64"); let subgraph = DeploymentHash::new(subgraph.clone()).map_err(|_| { StoreError::Unknown(anyhow!( diff --git a/store/postgres/src/detail.rs b/store/postgres/src/detail.rs index aa6e4811da2..3be2116c12b 100644 --- a/store/postgres/src/detail.rs +++ b/store/postgres/src/detail.rs @@ -116,7 +116,7 @@ impl TryFrom for SubgraphError { block_range, } = value; let block_number = crate::block_range::first_block_in_range(&block_range); - let block_hash = block_hash.map(|hash| H256::from_slice(hash.as_slice())); + let block_hash = block_hash.map(|hash| H256::from_slice(&hash.as_slice()[0..32])); // In existing databases, we have errors that have a `block_range` of // `UNVERSIONED_RANGE`, which leads to `None` as the block number, but // has a hash. Conversely, it is also possible for an error to not have a @@ -146,7 +146,7 @@ pub(crate) fn block( ) -> Result, StoreError> { match (&hash, &number) { (Some(hash), Some(number)) => { - let hash = H256::from_slice(hash.as_slice()); + let hash = H256::from_slice(&hash.as_slice()[0..32]); let number = number.to_u64().ok_or_else(|| { constraint_violation!( "the block number {} for {} in {} is not representable as a u64", From a9dadb4e6f3687c5584a81c39a85a165e0beed4c Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Thu, 21 Apr 2022 19:57:30 +0800 Subject: [PATCH 12/19] feat(node): update logs for arweave --- graph/src/blockchain/mod.rs | 1 + node/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/graph/src/blockchain/mod.rs b/graph/src/blockchain/mod.rs index 16bf472bd2e..3589db7b5b4 100644 --- a/graph/src/blockchain/mod.rs +++ b/graph/src/blockchain/mod.rs @@ -337,6 +337,7 @@ impl FromStr for BlockchainKind { fn from_str(s: &str) -> Result { match s { + "arweave" => Ok(BlockchainKind::Arweave), "ethereum" => Ok(BlockchainKind::Ethereum), "near" => Ok(BlockchainKind::Near), "tendermint" => Ok(BlockchainKind::Tendermint), diff --git a/node/src/main.rs b/node/src/main.rs index a4c820eaa94..e3ac2bb2dfb 100644 --- a/node/src/main.rs +++ b/node/src/main.rs @@ -575,7 +575,7 @@ fn arweave_networks_as_chains( .or_else(|| { error!( logger, - "No store configured for NEAR chain {}; ignoring this chain", chain_id + "No store configured for Arweave chain {}; ignoring this chain", chain_id ); None }) From 86089523aae22c567774148b50d069c024979387 Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Thu, 21 Apr 2022 20:35:13 +0800 Subject: [PATCH 13/19] docs(workaround)!: add FIXME --- graph/src/blockchain/types.rs | 2 +- store/postgres/src/chain_store.rs | 5 ++++- store/postgres/src/deployment.rs | 5 ++++- store/postgres/src/detail.rs | 5 ++++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/graph/src/blockchain/types.rs b/graph/src/blockchain/types.rs index fe9852cf093..4a02ce6c922 100644 --- a/graph/src/blockchain/types.rs +++ b/graph/src/blockchain/types.rs @@ -108,7 +108,7 @@ impl BlockPtr { // // workaround for arweave pub fn hash_as_h256(&self) -> H256 { - H256::from_slice(&self.hash_slice()[0..32]) + H256::from_slice(&self.hash_slice()[..32]) } pub fn hash_slice(&self) -> &[u8] { diff --git a/store/postgres/src/chain_store.rs b/store/postgres/src/chain_store.rs index 475dca92a94..d4f5d2bfa9d 100644 --- a/store/postgres/src/chain_store.rs +++ b/store/postgres/src/chain_store.rs @@ -1446,7 +1446,10 @@ impl ChainStoreTrait for ChainStore { .map(|(hash_opt, number_opt)| match (hash_opt, number_opt) { (Some(hash), Some(number)) => Some( ( - H256::from_slice(&hex::decode(hash).unwrap()[0..32]), + // FIXME: + // + // workaround for arweave + H256::from_slice(&hex::decode(hash).unwrap()[..32]), *number, ) .into(), diff --git a/store/postgres/src/deployment.rs b/store/postgres/src/deployment.rs index 2536100872c..73c0e704bfa 100644 --- a/store/postgres/src/deployment.rs +++ b/store/postgres/src/deployment.rs @@ -158,7 +158,10 @@ fn graft( match graft { (None, None, None) => Ok(None), (Some(subgraph), Some(hash), Some(block)) => { - let hash = H256::from_slice(&hash.as_slice()[0..32]); + // FIXME: + // + // workaround for arweave + let hash = H256::from_slice(&hash.as_slice()[..32]); let block = block.to_u64().expect("block numbers fit into a u64"); let subgraph = DeploymentHash::new(subgraph.clone()).map_err(|_| { StoreError::Unknown(anyhow!( diff --git a/store/postgres/src/detail.rs b/store/postgres/src/detail.rs index 3be2116c12b..c360114c5ce 100644 --- a/store/postgres/src/detail.rs +++ b/store/postgres/src/detail.rs @@ -116,7 +116,10 @@ impl TryFrom for SubgraphError { block_range, } = value; let block_number = crate::block_range::first_block_in_range(&block_range); - let block_hash = block_hash.map(|hash| H256::from_slice(&hash.as_slice()[0..32])); + // FIXME: + // + // workaround for arweave + let block_hash = block_hash.map(|hash| H256::from_slice(&hash.as_slice()[..32])); // In existing databases, we have errors that have a `block_range` of // `UNVERSIONED_RANGE`, which leads to `None` as the block number, but // has a hash. Conversely, it is also possible for an error to not have a From c3f2a29900254e39259827a851624ab1e9ef07c1 Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Tue, 26 Apr 2022 17:16:56 +0800 Subject: [PATCH 14/19] feat(chain): update TriggersAdapter in Arweave --- chain/arweave/src/chain.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/chain/arweave/src/chain.rs b/chain/arweave/src/chain.rs index 0d8001fab96..f15ec6f47e2 100644 --- a/chain/arweave/src/chain.rs +++ b/chain/arweave/src/chain.rs @@ -11,7 +11,7 @@ use graph::{ FirehoseMapper as FirehoseMapperTrait, TriggersAdapter as TriggersAdapterTrait, }, firehose_block_stream::FirehoseBlockStream, - BlockHash, BlockPtr, Blockchain, IngestorError, + BlockHash, BlockPtr, Blockchain, IngestorError, RuntimeAdapter as RuntimeAdapterTrait, }, components::store::DeploymentLocator, firehose::{self as firehose, ForkStep}, @@ -77,8 +77,6 @@ impl Blockchain for Chain { type UnresolvedDataSourceTemplate = UnresolvedDataSourceTemplate; - type TriggersAdapter = TriggersAdapter; - type TriggerData = crate::trigger::ArweaveTrigger; type MappingTrigger = crate::trigger::ArweaveTrigger; @@ -87,14 +85,12 @@ impl Blockchain for Chain { type NodeCapabilities = crate::capabilities::NodeCapabilities; - type RuntimeAdapter = RuntimeAdapter; - fn triggers_adapter( &self, _loc: &DeploymentLocator, _capabilities: &Self::NodeCapabilities, _unified_api_version: UnifiedMappingApiVersion, - ) -> Result, Error> { + ) -> Result>, Error> { let adapter = TriggersAdapter {}; Ok(Arc::new(adapter)) } @@ -171,7 +167,7 @@ impl Blockchain for Chain { .await } - fn runtime_adapter(&self) -> Arc { + fn runtime_adapter(&self) -> Arc> { Arc::new(RuntimeAdapter {}) } @@ -246,7 +242,7 @@ impl FirehoseMapperTrait for FirehoseMapper { &self, logger: &Logger, response: &firehose::Response, - adapter: &TriggersAdapter, + adapter: &Arc>, filter: &TriggerFilter, ) -> Result, FirehoseError> { let step = ForkStep::from_i32(response.step).unwrap_or_else(|| { From cf7bf5610db2a4438feb87aacca7307e666060ef Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Wed, 27 Apr 2022 22:09:44 +0800 Subject: [PATCH 15/19] chore(chain): fix typos in arweave implementation --- chain/arweave/src/chain.rs | 4 ++-- chain/arweave/src/data_source.rs | 28 ++++++++++++++-------------- graph/src/runtime/mod.rs | 2 +- node/src/main.rs | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/chain/arweave/src/chain.rs b/chain/arweave/src/chain.rs index f15ec6f47e2..d1f3166ef9d 100644 --- a/chain/arweave/src/chain.rs +++ b/chain/arweave/src/chain.rs @@ -144,7 +144,7 @@ impl Blockchain for Chain { _filter: Arc, _unified_api_version: UnifiedMappingApiVersion, ) -> Result>, Error> { - panic!("ARWEAVE does not support polling block stream") + panic!("Arweave does not support polling block stream") } fn chain_store(&self) -> Arc { @@ -224,7 +224,7 @@ impl TriggersAdapterTrait for TriggersAdapter { /// Panics if `block` is genesis. /// But that's ok since this is only called when reverting `block`. async fn parent_ptr(&self, block: &BlockPtr) -> Result, Error> { - // FIXME (ARWEAVE): Might not be necessary for ARWEAVE support for now + // FIXME (Arweave): Might not be necessary for Arweave support for now Ok(Some(BlockPtr { hash: BlockHash::from(vec![0xff; 48]), number: block.number.saturating_sub(1), diff --git a/chain/arweave/src/data_source.rs b/chain/arweave/src/data_source.rs index a12fa26e53d..061dcb9b5b0 100644 --- a/chain/arweave/src/data_source.rs +++ b/chain/arweave/src/data_source.rs @@ -110,7 +110,7 @@ impl blockchain::DataSource for DataSource { } fn as_stored_dynamic_data_source(&self) -> StoredDynamicDataSource { - // FIXME (ARWEAVE): Implement me! + // FIXME (Arweave): Implement me! todo!() } @@ -118,7 +118,7 @@ impl blockchain::DataSource for DataSource { _templates: &BTreeMap<&str, &DataSourceTemplate>, _stored: StoredDynamicDataSource, ) -> Result { - // FIXME (ARWEAVE): Implement me correctly + // FIXME (Arweave): Implement me correctly todo!() } @@ -133,19 +133,19 @@ impl blockchain::DataSource for DataSource { )) } - // Validate that there is a `source` address if there are receipt handlers + // Validate that there is a `source` address if there are transaction handlers let no_source_address = self.address().is_none(); - let has_receipt_handlers = !self.mapping.receipt_handlers.is_empty(); - if no_source_address && has_receipt_handlers { + let has_transaction_handlers = !self.mapping.transaction_handlers.is_empty(); + if no_source_address && has_transaction_handlers { errors.push(SubgraphManifestValidationError::SourceAddressRequired.into()); }; - // Validate that there are no more than one of both block handlers and receipt handlers + // Validate that there are no more than one of both block handlers and transaction handlers if self.mapping.block_handlers.len() > 1 { errors.push(anyhow!("data source has duplicated block handlers")); } - if self.mapping.receipt_handlers.len() > 1 { - errors.push(anyhow!("data source has duplicated receipt handlers")); + if self.mapping.transaction_handlers.len() > 1 { + errors.push(anyhow!("data source has duplicated transaction handlers")); } errors @@ -214,7 +214,7 @@ impl blockchain::UnresolvedDataSource for UnresolvedDataSource { context, } = self; - info!(logger, "Resolve data source"; "name" => &name, "source_account" => format_args!("{:?}", source.account), "source_start_block" => source.start_block); + info!(logger, "Resolve data source"; "name" => &name, "source_address" => format_args!("{:?}", source.account), "source_start_block" => source.start_block); let mapping = mapping.resolve(resolver, logger).await?; @@ -292,7 +292,7 @@ pub struct UnresolvedMapping { #[serde(default)] pub block_handlers: Vec, #[serde(default)] - pub receipt_handlers: Vec, + pub transaction_handlers: Vec, pub file: Link, } @@ -307,7 +307,7 @@ impl UnresolvedMapping { language, entities, block_handlers, - receipt_handlers, + transaction_handlers, file: link, } = self; @@ -321,7 +321,7 @@ impl UnresolvedMapping { language, entities, block_handlers, - receipt_handlers, + transaction_handlers, runtime: Arc::new(module_bytes), link, }) @@ -334,7 +334,7 @@ pub struct Mapping { pub language: String, pub entities: Vec, pub block_handlers: Vec, - pub receipt_handlers: Vec, + pub transaction_handlers: Vec, pub runtime: Arc>, pub link: Link, } @@ -345,7 +345,7 @@ pub struct MappingBlockHandler { } #[derive(Clone, Debug, Hash, Eq, PartialEq, Deserialize)] -pub struct ReceiptHandler { +pub struct TransactionHandler { handler: String, } diff --git a/graph/src/runtime/mod.rs b/graph/src/runtime/mod.rs index 7217453aa1e..4de127e0624 100644 --- a/graph/src/runtime/mod.rs +++ b/graph/src/runtime/mod.rs @@ -327,7 +327,7 @@ pub enum IndexForAscTypeId { ArweaveTransactionArray = 2503, ArweaveTag = 2504, ArweaveTagArray = 2505, - // Continue to add more Tendermint type IDs here. + // Continue to add more Arweave type IDs here. // e.g.: // NextArweaveType = 2505, // AnotherArweaveType = 2506, diff --git a/node/src/main.rs b/node/src/main.rs index a4b29502698..f4c474ca929 100644 --- a/node/src/main.rs +++ b/node/src/main.rs @@ -559,7 +559,7 @@ async fn main() { futures::future::pending::<()>().await; } -/// Return the hashmap of NEAR chains and also add them to `blockchain_map`. +/// Return the hashmap of Arweave chains and also add them to `blockchain_map`. fn arweave_networks_as_chains( blockchain_map: &mut BlockchainMap, logger: &Logger, From 182779f42bf474a06d0b1965f8e677b257917491 Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Wed, 27 Apr 2022 22:11:56 +0800 Subject: [PATCH 16/19] chore(chain): add gitignore in the arweave implementation --- chain/arweave/.gitignore | 1 + chain/arweave/src/protobuf/google.protobuf.rs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 chain/arweave/.gitignore delete mode 100644 chain/arweave/src/protobuf/google.protobuf.rs diff --git a/chain/arweave/.gitignore b/chain/arweave/.gitignore new file mode 100644 index 00000000000..97442b5f148 --- /dev/null +++ b/chain/arweave/.gitignore @@ -0,0 +1 @@ +google.protobuf.rs \ No newline at end of file diff --git a/chain/arweave/src/protobuf/google.protobuf.rs b/chain/arweave/src/protobuf/google.protobuf.rs deleted file mode 100644 index 8b137891791..00000000000 --- a/chain/arweave/src/protobuf/google.protobuf.rs +++ /dev/null @@ -1 +0,0 @@ - From ae9c56a1eab05f30f73ee0494db1cf05392dbc53 Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Thu, 28 Apr 2022 00:57:06 +0800 Subject: [PATCH 17/19] feat(chain): add transaction filter for arweave --- Cargo.lock | 11 ++++- chain/arweave/Cargo.toml | 2 +- chain/arweave/src/adapter.rs | 62 +++++++++++++++++--------- chain/arweave/src/chain.rs | 25 +++++++++-- chain/arweave/src/data_source.rs | 22 ++++++--- chain/arweave/src/runtime/abi.rs | 35 ++++++++++++--- chain/arweave/src/runtime/generated.rs | 13 +++++- chain/arweave/src/trigger.rs | 33 ++++++++++++++ graph/src/runtime/mod.rs | 13 +++--- 9 files changed, 169 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 32bd062463e..171f286c936 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,6 +180,15 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64-url" +version = "1.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a99c239d0c7e77c85dddfa9cebce48704b3c49550fcd3b84dd637e4484899f" +dependencies = [ + "base64", +] + [[package]] name = "bigdecimal" version = "0.1.2" @@ -1401,7 +1410,7 @@ dependencies = [ name = "graph-chain-arweave" version = "0.26.0" dependencies = [ - "base64", + "base64-url", "diesel", "graph", "graph-core", diff --git a/chain/arweave/Cargo.toml b/chain/arweave/Cargo.toml index 62c1d18eb93..7f78a872f3b 100644 --- a/chain/arweave/Cargo.toml +++ b/chain/arweave/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" tonic-build = "0.5.1" [dependencies] -base64 = "0.13" +base64-url = "1.4.13" graph = { path = "../../graph" } prost = "0.8.0" prost-types = "0.8.0" diff --git a/chain/arweave/src/adapter.rs b/chain/arweave/src/adapter.rs index 41f6a69743f..fbf53eb8c9b 100644 --- a/chain/arweave/src/adapter.rs +++ b/chain/arweave/src/adapter.rs @@ -1,24 +1,24 @@ use crate::capabilities::NodeCapabilities; use crate::{data_source::DataSource, Chain}; use graph::blockchain as bc; -use graph::firehose::BasicReceiptFilter; use graph::prelude::*; -use prost::Message; -use prost_types::Any; - -const BASIC_RECEIPT_FILTER_TYPE_URL: &str = - "type.googleapis.com/sf.arweave.transform.v1.BasicReceiptFilter"; +use std::collections::HashSet; #[derive(Clone, Debug, Default)] pub struct TriggerFilter { pub(crate) block_filter: ArweaveBlockFilter, + pub(crate) transaction_filter: ArweaveTransactionFilter, } impl bc::TriggerFilter for TriggerFilter { fn extend<'a>(&mut self, data_sources: impl Iterator + Clone) { - let TriggerFilter { block_filter } = self; + let TriggerFilter { + block_filter, + transaction_filter, + } = self; - block_filter.extend(ArweaveBlockFilter::from_data_sources(data_sources)); + block_filter.extend(ArweaveBlockFilter::from_data_sources(data_sources.clone())); + transaction_filter.extend(ArweaveTransactionFilter::from_data_sources(data_sources)); } fn node_capabilities(&self) -> NodeCapabilities { @@ -32,23 +32,41 @@ impl bc::TriggerFilter for TriggerFilter { } fn to_firehose_filter(self) -> Vec { - let TriggerFilter { - block_filter: block, - } = self; + vec![] + } +} - if block.trigger_every_block { - return vec![]; - } +/// ArweaveBlockFilter will match every block regardless of source being set. +/// see docs: https://thegraph.com/docs/en/supported-networks/arweave/ +#[derive(Clone, Debug, Default)] +pub(crate) struct ArweaveTransactionFilter { + owners: HashSet>, +} - // # NOTE - // - // Arweave don't have receipts - let filter = BasicReceiptFilter { accounts: vec![] }; +impl ArweaveTransactionFilter { + pub fn matches(&self, owner: &[u8]) -> bool { + self.owners.contains(owner) + } + + pub fn from_data_sources<'a>(iter: impl IntoIterator) -> Self { + let owners: Vec> = iter + .into_iter() + .filter(|data_source| { + data_source.source.owner.is_some() + && !data_source.mapping.transaction_handlers.is_empty() + }) + .map(|ds| { + base64_url::decode(&ds.source.owner.clone().unwrap_or_default()).unwrap_or_default() + }) + .collect(); + + Self { + owners: HashSet::from_iter(owners), + } + } - vec![Any { - type_url: BASIC_RECEIPT_FILTER_TYPE_URL.into(), - value: filter.encode_to_vec(), - }] + pub fn extend(&mut self, other: ArweaveTransactionFilter) { + self.owners.extend(other.owners); } } diff --git a/chain/arweave/src/chain.rs b/chain/arweave/src/chain.rs index d1f3166ef9d..01fefd05042 100644 --- a/chain/arweave/src/chain.rs +++ b/chain/arweave/src/chain.rs @@ -24,7 +24,7 @@ use crate::adapter::TriggerFilter; use crate::capabilities::NodeCapabilities; use crate::data_source::{DataSourceTemplate, UnresolvedDataSourceTemplate}; use crate::runtime::RuntimeAdapter; -use crate::trigger::ArweaveTrigger; +use crate::trigger::{self, ArweaveTrigger}; use crate::{ codec, data_source::{DataSource, UnresolvedDataSource}, @@ -198,9 +198,26 @@ impl TriggersAdapterTrait for TriggersAdapter { // TODO: Find the best place to introduce an `Arc` and avoid this clone. let shared_block = Arc::new(block.clone()); - let TriggerFilter { block_filter } = filter; - - let mut trigger_data: Vec = Vec::new(); + let TriggerFilter { + block_filter, + transaction_filter, + } = filter; + + let txs = block + .clone() + .txs + .into_iter() + .filter(|tx| transaction_filter.matches(&tx.owner)) + .map(|tx| trigger::TransactionWithBlockPtr { + tx: Arc::new(tx.clone()), + block: shared_block.clone(), + }) + .collect::>(); + + let mut trigger_data: Vec<_> = txs + .into_iter() + .map(|tx| ArweaveTrigger::Transaction(Arc::new(tx))) + .collect(); if block_filter.trigger_every_block { trigger_data.push(ArweaveTrigger::Block(shared_block.cheap_clone())); diff --git a/chain/arweave/src/data_source.rs b/chain/arweave/src/data_source.rs index 061dcb9b5b0..e6e3314c498 100644 --- a/chain/arweave/src/data_source.rs +++ b/chain/arweave/src/data_source.rs @@ -32,8 +32,11 @@ pub struct DataSource { } impl blockchain::DataSource for DataSource { + // FIXME + // + // need to decode the base64url encoding? fn address(&self) -> Option<&[u8]> { - self.source.account.as_ref().map(String::as_bytes) + self.source.owner.as_ref().map(String::as_bytes) } fn start_block(&self) -> BlockNumber { @@ -56,6 +59,11 @@ impl blockchain::DataSource for DataSource { Some(handler) => &handler.handler, None => return Ok(None), }, + // A transaction trigger matches if a transaction handler is present. + ArweaveTrigger::Transaction(_) => match self.handler_for_transaction() { + Some(handler) => &handler.handler, + None => return Ok(None), + }, }; Ok(Some(TriggerWithHandler::new( @@ -186,6 +194,10 @@ impl DataSource { fn handler_for_block(&self) -> Option<&MappingBlockHandler> { self.mapping.block_handlers.first() } + + fn handler_for_transaction(&self) -> Option<&TransactionHandler> { + self.mapping.transaction_handlers.first() + } } #[derive(Clone, Debug, Eq, PartialEq, Deserialize)] @@ -214,7 +226,7 @@ impl blockchain::UnresolvedDataSource for UnresolvedDataSource { context, } = self; - info!(logger, "Resolve data source"; "name" => &name, "source_address" => format_args!("{:?}", source.account), "source_start_block" => source.start_block); + info!(logger, "Resolve data source"; "name" => &name, "source_address" => format_args!("{:?}", base64_url::encode(&source.owner.clone().unwrap_or_default())), "source_start_block" => source.start_block); let mapping = mapping.resolve(resolver, logger).await?; @@ -346,13 +358,13 @@ pub struct MappingBlockHandler { #[derive(Clone, Debug, Hash, Eq, PartialEq, Deserialize)] pub struct TransactionHandler { - handler: String, + pub handler: String, } #[derive(Clone, Debug, Hash, Eq, PartialEq, Deserialize)] pub(crate) struct Source { - // A data source that does not have an account can only have block handlers. - pub(crate) account: Option, + // A data source that does not have an owner can only have block handlers. + pub(crate) owner: Option, #[serde(rename = "startBlock", default)] pub(crate) start_block: BlockNumber, } diff --git a/chain/arweave/src/runtime/abi.rs b/chain/arweave/src/runtime/abi.rs index 069f1706298..4f3d4005dc8 100644 --- a/chain/arweave/src/runtime/abi.rs +++ b/chain/arweave/src/runtime/abi.rs @@ -1,7 +1,8 @@ use crate::codec; +use crate::trigger::TransactionWithBlockPtr; use graph::runtime::gas::GasCounter; use graph::runtime::{asc_new, AscHeap, AscPtr, DeterministicHostError, ToAscObj}; -use graph_runtime_wasm::asc_abi::class::Array; +use graph_runtime_wasm::asc_abi::class::{Array, Uint8Array}; pub(crate) use super::generated::*; @@ -18,16 +19,16 @@ impl ToAscObj for codec::Tag { } } -impl ToAscObj for Vec { +impl ToAscObj for Vec> { fn to_asc_obj( &self, heap: &mut H, gas: &GasCounter, ) -> Result { let content = self - .iter() - .map(|x| asc_new(heap, x, gas)) - .collect::, _>>()?; + .into_iter() + .map(|x| asc_new(heap, x.as_slice(), gas)) + .collect::>, _>>()?; Ok(AscTransactionArray(Array::new(&*content, heap, gas)?)) } } @@ -109,7 +110,6 @@ impl ToAscObj for codec::Block { gas: &GasCounter, ) -> Result { Ok(AscBlock { - // ver: self.ver, indep_hash: asc_new(heap, self.indep_hash.as_slice(), gas)?, nonce: asc_new(heap, self.nonce.as_slice(), gas)?, previous_block: asc_new(heap, self.previous_block.as_slice(), gas)?, @@ -123,7 +123,15 @@ impl ToAscObj for codec::Block { height: self.height, hash: asc_new(heap, self.hash.as_slice(), gas)?, tx_root: asc_new(heap, self.tx_root.as_slice(), gas)?, - txs: asc_new(heap, &self.txs, gas)?, + txs: asc_new( + heap, + &self + .txs + .iter() + .map(|tx| tx.id.clone().into()) + .collect::>>(), + gas, + )?, wallet_list: asc_new(heap, self.wallet_list.as_slice(), gas)?, reward_addr: asc_new(heap, self.reward_addr.as_slice(), gas)?, tags: asc_new(heap, &self.tags, gas)?, @@ -168,3 +176,16 @@ impl ToAscObj for codec::Block { }) } } + +impl ToAscObj for TransactionWithBlockPtr { + fn to_asc_obj( + &self, + heap: &mut H, + gas: &GasCounter, + ) -> Result { + Ok(AscTransactionWithBlockPtr { + tx: asc_new(heap, &self.tx.as_ref(), gas)?, + block: asc_new(heap, self.block.as_ref(), gas)?, + }) + } +} diff --git a/chain/arweave/src/runtime/generated.rs b/chain/arweave/src/runtime/generated.rs index c14074de358..ff9ee87aa1c 100644 --- a/chain/arweave/src/runtime/generated.rs +++ b/chain/arweave/src/runtime/generated.rs @@ -78,7 +78,7 @@ impl AscIndexId for AscTag { } #[repr(C)] -pub struct AscTransactionArray(pub(crate) Array>); +pub struct AscTransactionArray(pub(crate) Array>); impl AscType for AscTransactionArray { fn to_asc_bytes(&self) -> Result, DeterministicHostError> { @@ -116,3 +116,14 @@ impl AscType for AscTagArray { impl AscIndexId for AscTagArray { const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::ArweaveTagArray; } + +#[repr(C)] +#[derive(AscType)] +pub struct AscTransactionWithBlockPtr { + pub tx: AscPtr, + pub block: AscPtr, +} + +impl AscIndexId for AscTransactionWithBlockPtr { + const INDEX_ASC_TYPE_ID: IndexForAscTypeId = IndexForAscTypeId::ArweaveTransactionWithBlockPtr; +} diff --git a/chain/arweave/src/trigger.rs b/chain/arweave/src/trigger.rs index a9a2553d9eb..3963795b666 100644 --- a/chain/arweave/src/trigger.rs +++ b/chain/arweave/src/trigger.rs @@ -19,10 +19,14 @@ impl std::fmt::Debug for ArweaveTrigger { #[derive(Debug)] pub enum MappingTriggerWithoutBlock { Block, + Transaction(Arc), } let trigger_without_block = match self { ArweaveTrigger::Block(_) => MappingTriggerWithoutBlock::Block, + ArweaveTrigger::Transaction(tx) => { + MappingTriggerWithoutBlock::Transaction(tx.tx.clone()) + } }; write!(f, "{:?}", trigger_without_block) @@ -37,6 +41,7 @@ impl blockchain::MappingTrigger for ArweaveTrigger { ) -> Result, DeterministicHostError> { Ok(match self { ArweaveTrigger::Block(block) => asc_new(heap, block.as_ref(), gas)?.erase(), + ArweaveTrigger::Transaction(tx) => asc_new(heap, tx.as_ref(), gas)?.erase(), }) } } @@ -44,12 +49,14 @@ impl blockchain::MappingTrigger for ArweaveTrigger { #[derive(Clone)] pub enum ArweaveTrigger { Block(Arc), + Transaction(Arc), } impl CheapClone for ArweaveTrigger { fn cheap_clone(&self) -> ArweaveTrigger { match self { ArweaveTrigger::Block(block) => ArweaveTrigger::Block(block.cheap_clone()), + ArweaveTrigger::Transaction(tx) => ArweaveTrigger::Transaction(tx.cheap_clone()), } } } @@ -58,6 +65,8 @@ impl PartialEq for ArweaveTrigger { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Block(a_ptr), Self::Block(b_ptr)) => a_ptr == b_ptr, + (Self::Transaction(a_tx), Self::Transaction(b_tx)) => a_tx.tx.id == b_tx.tx.id, + _ => false, } } } @@ -68,12 +77,14 @@ impl ArweaveTrigger { pub fn block_number(&self) -> BlockNumber { match self { ArweaveTrigger::Block(block) => block.number(), + ArweaveTrigger::Transaction(tx) => tx.block.number(), } } pub fn block_hash(&self) -> H256 { match self { ArweaveTrigger::Block(block) => block.ptr().hash_as_h256(), + ArweaveTrigger::Transaction(tx) => tx.block.ptr().hash_as_h256(), } } } @@ -83,6 +94,14 @@ impl Ord for ArweaveTrigger { match (self, other) { // Keep the order when comparing two block triggers (Self::Block(..), Self::Block(..)) => Ordering::Equal, + + // Block triggers always come last + (Self::Block(..), _) => Ordering::Greater, + (_, Self::Block(..)) => Ordering::Less, + + // Execution outcomes have no intrinsic ordering information so we keep the order in + // which they are included in the `txs` field of `Block`. + (Self::Transaction(..), Self::Transaction(..)) => Ordering::Equal, } } } @@ -99,6 +118,20 @@ impl TriggerData for ArweaveTrigger { ArweaveTrigger::Block(..) => { format!("Block #{} ({})", self.block_number(), self.block_hash()) } + ArweaveTrigger::Transaction(tx) => { + format!( + "Tx #{}, block #{}({})", + base64_url::encode(&tx.tx.id), + self.block_number(), + self.block_hash() + ) + } } } } + +pub struct TransactionWithBlockPtr { + // REVIEW: Do we want to actually also have those two below behind an `Arc` wrapper? + pub tx: Arc, + pub block: Arc, +} diff --git a/graph/src/runtime/mod.rs b/graph/src/runtime/mod.rs index 4de127e0624..cf45ef5a96b 100644 --- a/graph/src/runtime/mod.rs +++ b/graph/src/runtime/mod.rs @@ -323,14 +323,15 @@ pub enum IndexForAscTypeId { // Arweave types ArweaveBlock = 2500, ArweaveProofOfAccess = 2501, - ArweaveTransaction = 2502, - ArweaveTransactionArray = 2503, - ArweaveTag = 2504, - ArweaveTagArray = 2505, + ArweaveTag = 2502, + ArweaveTagArray = 2503, + ArweaveTransaction = 2504, + ArweaveTransactionArray = 2505, + ArweaveTransactionWithBlockPtr = 2506, // Continue to add more Arweave type IDs here. // e.g.: - // NextArweaveType = 2505, - // AnotherArweaveType = 2506, + // NextArweaveType = 2507, + // AnotherArweaveType = 2508, // ... // LastArweaveType = 3499, From 770097e93ee8d192a7a3872d0049c4ac1126804c Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Fri, 6 May 2022 11:12:05 +0800 Subject: [PATCH 18/19] feat(chain): update the tonic version in arweave --- chain/arweave/Cargo.toml | 6 +- chain/arweave/build.rs | 1 - .../src/protobuf/sf.arweave.r#type.v1.rs | 78 +++++++++---------- chain/arweave/src/runtime/generated.rs | 1 - 4 files changed, 42 insertions(+), 44 deletions(-) diff --git a/chain/arweave/Cargo.toml b/chain/arweave/Cargo.toml index 7f78a872f3b..25e6b0d9ede 100644 --- a/chain/arweave/Cargo.toml +++ b/chain/arweave/Cargo.toml @@ -4,13 +4,13 @@ version = "0.26.0" edition = "2021" [build-dependencies] -tonic-build = "0.5.1" +tonic-build = { version = "0.7.1", features = ["prost"]} [dependencies] base64-url = "1.4.13" graph = { path = "../../graph" } -prost = "0.8.0" -prost-types = "0.8.0" +prost = "0.10.1" +prost-types = "0.10.1" serde = "1.0" graph-runtime-wasm = { path = "../../runtime/wasm" } diff --git a/chain/arweave/build.rs b/chain/arweave/build.rs index 4a515f5c90e..e2ede2acef2 100644 --- a/chain/arweave/build.rs +++ b/chain/arweave/build.rs @@ -2,7 +2,6 @@ fn main() { println!("cargo:rerun-if-changed=proto"); tonic_build::configure() .out_dir("src/protobuf") - .format(true) .compile(&["proto/type.proto"], &["proto"]) .expect("Failed to compile Firehose Arweave proto(s)"); } diff --git a/chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs b/chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs index 75b85922ae2..98a1359305a 100644 --- a/chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs +++ b/chain/arweave/src/protobuf/sf.arweave.r#type.v1.rs @@ -1,141 +1,141 @@ #[derive(Clone, PartialEq, ::prost::Message)] pub struct BigInt { - #[prost(bytes = "vec", tag = "1")] + #[prost(bytes="vec", tag="1")] pub bytes: ::prost::alloc::vec::Vec, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct Block { /// Firehose block version (unrelated to Arweave block version) - #[prost(uint32, tag = "1")] + #[prost(uint32, tag="1")] pub ver: u32, /// The block identifier - #[prost(bytes = "vec", tag = "2")] + #[prost(bytes="vec", tag="2")] pub indep_hash: ::prost::alloc::vec::Vec, /// The nonce chosen to solve the mining problem - #[prost(bytes = "vec", tag = "3")] + #[prost(bytes="vec", tag="3")] pub nonce: ::prost::alloc::vec::Vec, /// `indep_hash` of the previous block in the weave - #[prost(bytes = "vec", tag = "4")] + #[prost(bytes="vec", tag="4")] pub previous_block: ::prost::alloc::vec::Vec, /// POSIX time of block discovery - #[prost(uint64, tag = "5")] + #[prost(uint64, tag="5")] pub timestamp: u64, /// POSIX time of the last difficulty retarget - #[prost(uint64, tag = "6")] + #[prost(uint64, tag="6")] pub last_retarget: u64, /// Mining difficulty; the number `hash` must be greater than. - #[prost(message, optional, tag = "7")] + #[prost(message, optional, tag="7")] pub diff: ::core::option::Option, /// How many blocks have passed since the genesis block - #[prost(uint64, tag = "8")] + #[prost(uint64, tag="8")] pub height: u64, /// Mining solution hash of the block; must satisfy the mining difficulty - #[prost(bytes = "vec", tag = "9")] + #[prost(bytes="vec", tag="9")] pub hash: ::prost::alloc::vec::Vec, /// Merkle root of the tree of Merkle roots of block's transactions' data. - #[prost(bytes = "vec", tag = "10")] + #[prost(bytes="vec", tag="10")] pub tx_root: ::prost::alloc::vec::Vec, /// Transactions contained within this block - #[prost(message, repeated, tag = "11")] + #[prost(message, repeated, tag="11")] pub txs: ::prost::alloc::vec::Vec, /// The root hash of the Merkle Patricia Tree containing /// all wallet (account) balances and the identifiers /// of the last transactions posted by them; if any. - #[prost(bytes = "vec", tag = "12")] + #[prost(bytes="vec", tag="12")] pub wallet_list: ::prost::alloc::vec::Vec, /// (string or) Address of the account to receive the block rewards. Can also be unclaimed which is encoded as a null byte - #[prost(bytes = "vec", tag = "13")] + #[prost(bytes="vec", tag="13")] pub reward_addr: ::prost::alloc::vec::Vec, /// Tags that a block producer can add to a block - #[prost(message, repeated, tag = "14")] + #[prost(message, repeated, tag="14")] pub tags: ::prost::alloc::vec::Vec, /// Size of reward pool - #[prost(message, optional, tag = "15")] + #[prost(message, optional, tag="15")] pub reward_pool: ::core::option::Option, /// Size of the weave in bytes - #[prost(message, optional, tag = "16")] + #[prost(message, optional, tag="16")] pub weave_size: ::core::option::Option, /// Size of this block in bytes - #[prost(message, optional, tag = "17")] + #[prost(message, optional, tag="17")] pub block_size: ::core::option::Option, /// Required after the version 1.8 fork. Zero otherwise. /// The sum of the average number of hashes computed /// by the network to produce the past blocks including this one. - #[prost(message, optional, tag = "18")] + #[prost(message, optional, tag="18")] pub cumulative_diff: ::core::option::Option, /// Required after the version 1.8 fork. Null byte otherwise. /// The Merkle root of the block index - the list of {`indep_hash`; `weave_size`; `tx_root`} triplets - #[prost(bytes = "vec", tag = "20")] + #[prost(bytes="vec", tag="20")] pub hash_list_merkle: ::prost::alloc::vec::Vec, /// The proof of access; Used after v2.4 only; set as defaults otherwise - #[prost(message, optional, tag = "21")] + #[prost(message, optional, tag="21")] pub poa: ::core::option::Option, } /// A succinct proof of access to a recall byte found in a TX #[derive(Clone, PartialEq, ::prost::Message)] pub struct ProofOfAccess { /// The recall byte option chosen; global offset of index byte - #[prost(string, tag = "1")] + #[prost(string, tag="1")] pub option: ::prost::alloc::string::String, /// The path through the Merkle tree of transactions' `data_root`s; /// from the `data_root` being proven to the corresponding `tx_root` - #[prost(bytes = "vec", tag = "2")] + #[prost(bytes="vec", tag="2")] pub tx_path: ::prost::alloc::vec::Vec, /// The path through the Merkle tree of identifiers of chunks of the /// corresponding transaction; from the chunk being proven to the /// corresponding `data_root`. - #[prost(bytes = "vec", tag = "3")] + #[prost(bytes="vec", tag="3")] pub data_path: ::prost::alloc::vec::Vec, /// The data chunk. - #[prost(bytes = "vec", tag = "4")] + #[prost(bytes="vec", tag="4")] pub chunk: ::prost::alloc::vec::Vec, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct Transaction { /// 1 or 2 for v1 or v2 transactions. More allowable in the future - #[prost(uint32, tag = "1")] + #[prost(uint32, tag="1")] pub format: u32, /// The transaction identifier. - #[prost(bytes = "vec", tag = "2")] + #[prost(bytes="vec", tag="2")] pub id: ::prost::alloc::vec::Vec, /// Either the identifier of the previous transaction from the same /// wallet or the identifier of one of the last ?MAX_TX_ANCHOR_DEPTH blocks. - #[prost(bytes = "vec", tag = "3")] + #[prost(bytes="vec", tag="3")] pub last_tx: ::prost::alloc::vec::Vec, /// The public key the transaction is signed with. - #[prost(bytes = "vec", tag = "4")] + #[prost(bytes="vec", tag="4")] pub owner: ::prost::alloc::vec::Vec, /// A list of arbitrary key-value pairs - #[prost(message, repeated, tag = "5")] + #[prost(message, repeated, tag="5")] pub tags: ::prost::alloc::vec::Vec, /// The address of the recipient; if any. The SHA2-256 hash of the public key. - #[prost(bytes = "vec", tag = "6")] + #[prost(bytes="vec", tag="6")] pub target: ::prost::alloc::vec::Vec, /// The amount of Winstons to send to the recipient; if any. - #[prost(message, optional, tag = "7")] + #[prost(message, optional, tag="7")] pub quantity: ::core::option::Option, /// The data to upload; if any. For v2 transactions; the field is optional /// - a fee is charged based on the `data_size` field; /// data may be uploaded any time later in chunks. - #[prost(bytes = "vec", tag = "8")] + #[prost(bytes="vec", tag="8")] pub data: ::prost::alloc::vec::Vec, /// Size in bytes of the transaction data. - #[prost(message, optional, tag = "9")] + #[prost(message, optional, tag="9")] pub data_size: ::core::option::Option, /// The Merkle root of the Merkle tree of data chunks. - #[prost(bytes = "vec", tag = "10")] + #[prost(bytes="vec", tag="10")] pub data_root: ::prost::alloc::vec::Vec, /// The signature. - #[prost(bytes = "vec", tag = "11")] + #[prost(bytes="vec", tag="11")] pub signature: ::prost::alloc::vec::Vec, /// The fee in Winstons. - #[prost(message, optional, tag = "12")] + #[prost(message, optional, tag="12")] pub reward: ::core::option::Option, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct Tag { - #[prost(bytes = "vec", tag = "1")] + #[prost(bytes="vec", tag="1")] pub name: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "2")] + #[prost(bytes="vec", tag="2")] pub value: ::prost::alloc::vec::Vec, } diff --git a/chain/arweave/src/runtime/generated.rs b/chain/arweave/src/runtime/generated.rs index ff9ee87aa1c..e8a10fdb158 100644 --- a/chain/arweave/src/runtime/generated.rs +++ b/chain/arweave/src/runtime/generated.rs @@ -6,7 +6,6 @@ use graph_runtime_wasm::asc_abi::class::{Array, AscString, Uint8Array}; #[repr(C)] #[derive(AscType, Default)] pub struct AscBlock { - // pub ver: u32, pub timestamp: u64, pub last_retarget: u64, pub height: u64, From 4898c6555937d64e66b1a29f7e036d49b678744b Mon Sep 17 00:00:00 2001 From: clearloop <26088946+clearloop@users.noreply.github.com> Date: Sat, 7 May 2022 00:02:55 +0800 Subject: [PATCH 19/19] chore(chain): skip fmt check for the generated proto file of arweave --- chain/arweave/src/codec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/chain/arweave/src/codec.rs b/chain/arweave/src/codec.rs index 267aad5f9cb..09da7fee1b0 100644 --- a/chain/arweave/src/codec.rs +++ b/chain/arweave/src/codec.rs @@ -1,3 +1,4 @@ +#[rustfmt::skip] #[path = "protobuf/sf.arweave.r#type.v1.rs"] mod pbcodec;