diff --git a/runtime-sdk/src/dispatcher.rs b/runtime-sdk/src/dispatcher.rs index 7337f7ff16..3a05d4bea2 100644 --- a/runtime-sdk/src/dispatcher.rs +++ b/runtime-sdk/src/dispatcher.rs @@ -36,6 +36,7 @@ use crate::{ modules::core::API as _, runtime::Runtime, schedule_control::ScheduleControlHost, + sender::SenderMeta, storage::{self, NestedStore, Prefix}, types, types::transaction::{AuthProof, Transaction}, @@ -77,6 +78,8 @@ pub struct DispatchResult { pub tags: Tags, /// Transaction priority. pub priority: u64, + /// Transaction sender metadata. + pub sender_metadata: SenderMeta, /// Call format metadata. pub call_format_metadata: callformat::Metadata, } @@ -91,6 +94,7 @@ impl DispatchResult { result, tags, priority: 0, + sender_metadata: Default::default(), call_format_metadata, } } @@ -258,8 +262,10 @@ impl Dispatcher { ); } - // Load priority, weights. + // Load priority. let priority = R::Core::take_priority(&mut ctx); + // Load sender metadata. + let sender_metadata = R::Core::take_sender_meta(&mut ctx); if ctx.is_check_only() { // Rollback state during checks. @@ -270,6 +276,7 @@ impl Dispatcher { result, tags: Vec::new(), priority, + sender_metadata, call_format_metadata, }, Vec::new(), @@ -282,6 +289,7 @@ impl Dispatcher { result, tags: etags.into_tags(), priority, + sender_metadata, call_format_metadata, }, messages, @@ -338,9 +346,9 @@ impl Dispatcher { error: Default::default(), meta: Some(CheckTxMetadata { priority: dispatch.priority, - sender: vec![], // TODO: Support indicating senders. - sender_seq: 0, // TODO: Support indicating senders. - sender_state_seq: 0, // TODO: Support indicating senders. + sender: dispatch.sender_metadata.id(), + sender_seq: dispatch.sender_metadata.tx_nonce, + sender_state_seq: dispatch.sender_metadata.state_nonce, }), }), diff --git a/runtime-sdk/src/lib.rs b/runtime-sdk/src/lib.rs index b002cb057f..9ab35e8fc1 100644 --- a/runtime-sdk/src/lib.rs +++ b/runtime-sdk/src/lib.rs @@ -16,6 +16,7 @@ pub mod module; pub mod modules; pub mod runtime; pub mod schedule_control; +pub mod sender; pub mod storage; pub mod testing; pub mod types; diff --git a/runtime-sdk/src/modules/core/mod.rs b/runtime-sdk/src/modules/core/mod.rs index 1a0daee94d..cde9b33373 100644 --- a/runtime-sdk/src/modules/core/mod.rs +++ b/runtime-sdk/src/modules/core/mod.rs @@ -18,6 +18,7 @@ use crate::{ self, CallResult, InvariantHandler as _, MethodHandler as _, Module as _, ModuleInfoHandler as _, }, + sender::SenderMeta, types::{ token, transaction::{self, AddressSpec, AuthProof, Call, CallFormat, UnverifiedTransaction}, @@ -266,6 +267,12 @@ pub trait API { /// Takes and returns the stored transaction priority. fn take_priority(ctx: &mut C) -> u64; + /// Set transaction sender metadata. + fn set_sender_meta(ctx: &mut C, meta: SenderMeta); + + /// Takes and returns the stored transaction sender metadata. + fn take_sender_meta(ctx: &mut C) -> SenderMeta; + /// Returns the configured max iterations in the binary search for the estimate /// gas. fn estimate_gas_search_max_iters(ctx: &C) -> u64; @@ -342,6 +349,7 @@ pub struct Module { const CONTEXT_KEY_GAS_USED: &str = "core.GasUsed"; const CONTEXT_KEY_PRIORITY: &str = "core.Priority"; +const CONTEXT_KEY_SENDER_META: &str = "core.SenderMeta"; impl Module { /// Initialize state from genesis. @@ -447,6 +455,16 @@ impl API for Module { .unwrap_or_default() } + fn set_sender_meta(ctx: &mut C, meta: SenderMeta) { + ctx.value::(CONTEXT_KEY_SENDER_META).set(meta); + } + + fn take_sender_meta(ctx: &mut C) -> SenderMeta { + ctx.value::(CONTEXT_KEY_SENDER_META) + .take() + .unwrap_or_default() + } + fn estimate_gas_search_max_iters(ctx: &C) -> u64 { ctx.local_config(MODULE_NAME) .as_ref() diff --git a/runtime-sdk/src/modules/core/test.rs b/runtime-sdk/src/modules/core/test.rs index 8b1fb8fe1e..997bcec417 100644 --- a/runtime-sdk/src/modules/core/test.rs +++ b/runtime-sdk/src/modules/core/test.rs @@ -10,6 +10,7 @@ use crate::{ module::{self, Module as _, TransactionHandler as _}, runtime::Runtime, sdk_derive, + sender::SenderMeta, testing::{configmap, keys, mock}, types::{token, transaction, transaction::CallerAddress}, }; @@ -749,6 +750,25 @@ fn test_add_priority_overflow() { ); } +#[test] +fn test_set_sender_meta() { + let mut mock = mock::Mock::default(); + let mut ctx = mock.create_ctx(); + + let sender_meta = SenderMeta { + address: keys::alice::address(), + tx_nonce: 42, + state_nonce: 43, + }; + Core::set_sender_meta(&mut ctx, sender_meta.clone()); + + let taken_sender_meta = Core::take_sender_meta(&mut ctx); + assert_eq!( + taken_sender_meta, sender_meta, + "setting sender metadata should work" + ); +} + #[test] fn test_min_gas_price() { let mut mock = mock::Mock::default(); diff --git a/runtime-sdk/src/sender.rs b/runtime-sdk/src/sender.rs new file mode 100644 index 0000000000..73a125f9c1 --- /dev/null +++ b/runtime-sdk/src/sender.rs @@ -0,0 +1,26 @@ +//! Transaction sender metadata. +use crate::types::address::Address; + +/// Transaction sender metadata. +#[derive(Clone, Debug, Eq, PartialEq, Default)] +pub struct SenderMeta { + /// Sender address. + pub address: Address, + /// Sender nonce contained in the transaction. + pub tx_nonce: u64, + /// Sender nonce contained in runtime state. + pub state_nonce: u64, +} + +impl SenderMeta { + /// Unique identifier of the sender, currently derived from the sender address. + pub fn id(&self) -> Vec { + if self.address == Default::default() { + // Use an empty value for the default address as that signals to the host that the + // sender should be ignored. + vec![] + } else { + self.address.into_bytes().to_vec() + } + } +}