Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime/consensus: Add support for querying round roots #1564

Merged
merged 2 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 54 additions & 3 deletions runtime-sdk/src/modules/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@
//! Low level consensus module for communicating with the consensus layer.
use std::{convert::TryInto, num::NonZeroUsize, str::FromStr, sync::Mutex};

use oasis_runtime_sdk_macros::handler;
use once_cell::sync::Lazy;
use thiserror::Error;

use oasis_core_runtime::{
common::versioned::Versioned,
common::{namespace::Namespace, versioned::Versioned},
consensus::{
beacon::EpochTime,
roothash::{Message, StakingMessage},
roothash::{Message, RoundRoots, StakingMessage},
staking,
staking::{Account as ConsensusAccount, Delegation as ConsensusDelegation},
state::{
beacon::ImmutableState as BeaconImmutableState,
roothash::ImmutableState as RoothashImmutableState,
staking::ImmutableState as StakingImmutableState, StateError,
},
HEIGHT_LATEST,
Expand All @@ -23,26 +25,40 @@ use oasis_core_runtime::{

use crate::{
context::{Context, TxContext},
core::common::crypto::hash::Hash,
history, migration, module,
module::{Module as _, Parameters as _},
modules, sdk_derive,
modules,
modules::core::API as _,
sdk_derive,
types::{
address::{Address, SignatureAddressSpec},
message::MessageEventHookInvocation,
token,
transaction::AddressSpec,
},
Runtime,
};

#[cfg(test)]
mod test;
pub mod types;

/// Unique module name.
const MODULE_NAME: &str = "consensus";

/// Gas costs.
#[derive(Clone, Debug, Default, PartialEq, Eq, cbor::Encode, cbor::Decode)]
pub struct GasCosts {
/// Cost of the internal round_root call.
pub round_root: u64,
}

/// Parameters for the consensus module.
#[derive(Clone, Debug, PartialEq, Eq, cbor::Encode, cbor::Decode)]
pub struct Parameters {
pub gas_costs: GasCosts,

pub consensus_denomination: token::Denomination,
pub consensus_scaling_factor: u64,

Expand All @@ -56,6 +72,7 @@ pub struct Parameters {
impl Default for Parameters {
fn default() -> Self {
Self {
gas_costs: Default::default(),
consensus_denomination: token::Denomination::from_str("TEST").unwrap(),
consensus_scaling_factor: 1,
min_delegate_amount: 0,
Expand Down Expand Up @@ -194,6 +211,13 @@ pub trait API {
/// Determine consensus height corresponding to the given epoch transition. This query may be
/// expensive in case the epoch is far back.
fn height_for_epoch<C: Context>(ctx: &C, epoch: EpochTime) -> Result<u64, Error>;

/// Round roots return the round roots for the given runtime ID and round.
fn round_roots<C: Context>(
ctx: &C,
runtime_id: Namespace,
round: u64,
) -> Result<Option<RoundRoots>, Error>;
}

pub struct Module;
Expand Down Expand Up @@ -231,6 +255,22 @@ impl Module {
// Set genesis parameters.
Self::set_params(genesis.parameters);
}

#[handler(call = "consensus.RoundRoot", internal)]
fn internal_round_root<C: TxContext>(
kostko marked this conversation as resolved.
Show resolved Hide resolved
ctx: &mut C,
body: types::RoundRootBody,
) -> Result<Option<Hash>, Error> {
let params = Self::params();
<C::Runtime as Runtime>::Core::use_tx_gas(ctx, params.gas_costs.round_root)?;

Ok(
Self::round_roots(ctx, body.runtime_id, body.round)?.map(|rr| match body.kind {
types::RootKind::IO => rr.io_root,
types::RootKind::State => rr.state_root,
}),
)
}
}

impl API for Module {
Expand Down Expand Up @@ -418,6 +458,17 @@ impl API for Module {
height -= 1;
}
}

fn round_roots<C: Context>(
ctx: &C,
runtime_id: Namespace,
round: u64,
) -> Result<Option<RoundRoots>, Error> {
let roothash = RoothashImmutableState::new(ctx.consensus_state());
roothash
.round_roots(runtime_id, round)
.map_err(Error::InternalStateError)
}
}

impl module::TransactionHandler for Module {}
Expand Down
3 changes: 3 additions & 0 deletions runtime-sdk/src/modules/consensus/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ fn test_query_parameters() {
let mut ctx = mock.create_ctx();

let params = Parameters {
gas_costs: Default::default(),
consensus_denomination: Denomination::NATIVE,
consensus_scaling_factor: 1_000,
min_delegate_amount: 10,
Expand All @@ -480,6 +481,7 @@ fn test_query_parameters() {
fn test_init_bad_scaling_factor_1() {
Consensus::init(Genesis {
parameters: Parameters {
gas_costs: Default::default(),
consensus_denomination: Denomination::NATIVE,
// Zero scaling factor is invalid.
consensus_scaling_factor: 0,
Expand All @@ -493,6 +495,7 @@ fn test_init_bad_scaling_factor_1() {
fn test_init_bad_scaling_factor_2() {
Consensus::init(Genesis {
parameters: Parameters {
gas_costs: Default::default(),
consensus_denomination: Denomination::NATIVE,
// Scaling factor that is not a power of 10 is invalid.
consensus_scaling_factor: 1230,
Expand Down
18 changes: 18 additions & 0 deletions runtime-sdk/src/modules/consensus/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use oasis_core_runtime::common::namespace::Namespace;

/// Kind of root.
#[derive(Clone, Debug, cbor::Encode, cbor::Decode)]
#[repr(u8)]
pub enum RootKind {
State = 1,
IO = 2,
}

/// Internal round root call body.
#[derive(Clone, Debug, cbor::Encode, cbor::Decode)]
#[cbor(no_default)]
pub struct RoundRootBody {
pub runtime_id: Namespace,
pub round: u64,
pub kind: RootKind,
}
2 changes: 1 addition & 1 deletion tests/e2e/contracts/subcall/evm_subcall.abi
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"inputs":[{"internalType":"uint64","name":"code","type":"uint64"},{"internalType":"bytes","name":"module","type":"bytes"}],"name":"SubcallFailed","type":"error"},{"inputs":[{"internalType":"bytes","name":"method","type":"bytes"},{"internalType":"bytes","name":"body","type":"bytes"}],"name":"test","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"method","type":"bytes"},{"internalType":"bytes","name":"body","type":"bytes"}],"name":"test_delegatecall","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"method","type":"bytes"},{"internalType":"bytes","name":"body","type":"bytes"}],"name":"test_spin","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"}]
[{"inputs":[{"internalType":"uint64","name":"code","type":"uint64"},{"internalType":"bytes","name":"module","type":"bytes"}],"name":"SubcallFailed","type":"error"},{"inputs":[{"internalType":"bytes","name":"method","type":"bytes"},{"internalType":"bytes","name":"body","type":"bytes"}],"name":"test","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"test_consensus_round_root","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"method","type":"bytes"},{"internalType":"bytes","name":"body","type":"bytes"}],"name":"test_delegatecall","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"method","type":"bytes"},{"internalType":"bytes","name":"body","type":"bytes"}],"name":"test_spin","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"}]
2 changes: 1 addition & 1 deletion tests/e2e/contracts/subcall/evm_subcall.hex
Original file line number Diff line number Diff line change
@@ -1 +1 @@
608060405234801561000f575f80fd5b5061062e8061001d5f395ff3fe608060405260043610610033575f3560e01c80630c5561a61461003757806323bfb16a1461006057806350d82f381461007f575b5f80fd5b61004a610045366004610377565b61009e565b604051610057919061042b565b60405180910390f35b34801561006b575f80fd5b5061004a61007a366004610377565b610162565b34801561008a575f80fd5b5061004a610099366004610377565b610212565b60605f80610103600160981b016001600160a01b0316878787876040516020016100cb9493929190610465565b60408051601f19818403018152908290526100e59161048b565b5f604051808303815f865af19150503d805f811461011e576040519150601f19603f3d011682016040523d82523d5f602084013e610123565b606091505b50915091508161014e5760405162461bcd60e51b8152600401610145906104a6565b60405180910390fd5b610157816102e1565b979650505050505050565b60605f80610103600160981b016001600160a01b03168787878760405160200161018f9493929190610465565b60408051601f19818403018152908290526101a99161048b565b5f60405180830381855af49150503d805f81146101e1576040519150601f19603f3d011682016040523d82523d5f602084013e6101e6565b606091505b5091509150816102085760405162461bcd60e51b8152600401610145906104a6565b9695505050505050565b60605f80610103600160981b016001600160a01b03168787878760405160200161023f9493929190610465565b60408051601f19818403018152908290526102599161048b565b5f604051808303815f865af19150503d805f8114610292576040519150601f19603f3d011682016040523d82523d5f602084013e610297565b606091505b5091509150816102b95760405162461bcd60e51b8152600401610145906104a6565b5f5b60648112156102d657806102ce816104ce565b9150506102bb565b509695505050505050565b60605f80838060200190518101906102f9919061050c565b915091508167ffffffffffffffff165f1461032b57818160405163575a7c4d60e01b81526004016101459291906105ce565b9392505050565b5f8083601f840112610342575f80fd5b50813567ffffffffffffffff811115610359575f80fd5b602083019150836020828501011115610370575f80fd5b9250929050565b5f805f806040858703121561038a575f80fd5b843567ffffffffffffffff808211156103a1575f80fd5b6103ad88838901610332565b909650945060208701359150808211156103c5575f80fd5b506103d287828801610332565b95989497509550505050565b5f5b838110156103f85781810151838201526020016103e0565b50505f910152565b5f81518084526104178160208601602086016103de565b601f01601f19169290920160200192915050565b602081525f61032b6020830184610400565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b604081525f61047860408301868861043d565b828103602084015261015781858761043d565b5f825161049c8184602087016103de565b9190910192915050565b6020808252600e908201526d1cdd5898d85b1b0819985a5b195960921b604082015260600190565b5f6001600160ff1b0182016104f157634e487b7160e01b5f52601160045260245ffd5b5060010190565b634e487b7160e01b5f52604160045260245ffd5b5f806040838503121561051d575f80fd5b825167ffffffffffffffff8082168214610535575f80fd5b602085015191935080821115610549575f80fd5b818501915085601f83011261055c575f80fd5b81518181111561056e5761056e6104f8565b604051601f8201601f19908116603f01168101908382118183101715610596576105966104f8565b816040528281528860208487010111156105ae575f80fd5b6105bf8360208301602088016103de565b80955050505050509250929050565b67ffffffffffffffff83168152604060208201525f6105f06040830184610400565b94935050505056fea26469706673582212202369658d710f3f71613ae8645e6c9ac9e88e7736389b455e83675353c8aed56664736f6c63430008150033
608060405234801561000f575f80fd5b506108308061001d5f395ff3fe60806040526004361061003e575f3560e01c80630c5561a61461004257806323bfb16a1461006b57806350d82f381461008a578063c7391861146100a9575b5f80fd5b61005561005036600461057e565b6100bd565b6040516100629190610632565b60405180910390f35b348015610076575f80fd5b5061005561008536600461057e565b610181565b348015610095575f80fd5b506100556100a436600461057e565b610231565b3480156100b4575f80fd5b506100556102f6565b60605f80610103600160981b016001600160a01b0316878787876040516020016100ea949392919061066c565b60408051601f198184030181529082905261010491610692565b5f604051808303815f865af19150503d805f811461013d576040519150601f19603f3d011682016040523d82523d5f602084013e610142565b606091505b50915091508161016d5760405162461bcd60e51b8152600401610164906106ad565b60405180910390fd5b610176816104e8565b979650505050505050565b60605f80610103600160981b016001600160a01b0316878787876040516020016101ae949392919061066c565b60408051601f19818403018152908290526101c891610692565b5f60405180830381855af49150503d805f8114610200576040519150601f19603f3d011682016040523d82523d5f602084013e610205565b606091505b5091509150816102275760405162461bcd60e51b8152600401610164906106ad565b9695505050505050565b60605f80610103600160981b016001600160a01b03168787878760405160200161025e949392919061066c565b60408051601f198184030181529082905261027891610692565b5f604051808303815f865af19150503d805f81146102b1576040519150601f19603f3d011682016040523d82523d5f602084013e6102b6565b606091505b5091509150816102d85760405162461bcd60e51b8152600401610164906106ad565b5f5b60648112156102eb576001016102da565b509695505050505050565b604080518082018252601381527218dbdb9cd95b9cdd5ccb949bdd5b99149bdbdd606a1b602080830191909152915160a360f81b92810192909252601960fa1b6021830152631ada5b9960e21b6022830152600160f81b6026830152606560f81b6027830152641c9bdd5b9960da1b6028830152600160f91b602d830152603560f91b602e830152691c9d5b9d1a5b5957da5960b21b602f830152600b60fb1b6039830152600160fd1b603a830152600160ff1b603b8301526060915f918291610103600160981b019190605b0160408051601f19818403018152908290526103e292916020016106d5565b60408051601f19818403018152908290526103fc91610692565b5f604051808303815f865af19150503d805f8114610435576040519150601f19603f3d011682016040523d82523d5f602084013e61043a565b606091505b5091509150816104985760405162461bcd60e51b815260206004820152602360248201527f636f6e73656e73757320726f756e6420726f6f742073756263616c6c206661696044820152621b195960ea1b6064820152608401610164565b5f80828060200190518101906104ae9190610716565b915091508167ffffffffffffffff165f146104e057818160405163575a7c4d60e01b81526004016101649291906107d8565b949350505050565b60605f80838060200190518101906105009190610716565b915091508167ffffffffffffffff165f1461053257818160405163575a7c4d60e01b81526004016101649291906107d8565b9392505050565b5f8083601f840112610549575f80fd5b50813567ffffffffffffffff811115610560575f80fd5b602083019150836020828501011115610577575f80fd5b9250929050565b5f805f8060408587031215610591575f80fd5b843567ffffffffffffffff808211156105a8575f80fd5b6105b488838901610539565b909650945060208701359150808211156105cc575f80fd5b506105d987828801610539565b95989497509550505050565b5f5b838110156105ff5781810151838201526020016105e7565b50505f910152565b5f815180845261061e8160208601602086016105e5565b601f01601f19169290920160200192915050565b602081525f6105326020830184610607565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b604081525f61067f604083018688610644565b8281036020840152610176818587610644565b5f82516106a38184602087016105e5565b9190910192915050565b6020808252600e908201526d1cdd5898d85b1b0819985a5b195960921b604082015260600190565b604081525f6106e76040830185610607565b82810360208401526106f98185610607565b95945050505050565b634e487b7160e01b5f52604160045260245ffd5b5f8060408385031215610727575f80fd5b825167ffffffffffffffff808216821461073f575f80fd5b602085015191935080821115610753575f80fd5b818501915085601f830112610766575f80fd5b81518181111561077857610778610702565b604051601f8201601f19908116603f011681019083821181831017156107a0576107a0610702565b816040528281528860208487010111156107b8575f80fd5b6107c98360208301602088016105e5565b80955050505050509250929050565b67ffffffffffffffff83168152604060208201525f6104e0604083018461060756fea264697066735822122029a34c1a7cda70295558c88edd184a88d6c65683f77f25fde5fae8ad4f1f735864736f6c63430008170033
76 changes: 67 additions & 9 deletions tests/e2e/contracts/subcall/evm_subcall.sol
Original file line number Diff line number Diff line change
@@ -1,33 +1,91 @@
pragma solidity ^0.8.0;

contract Test {
address private constant SUBCALL = 0x0100000000000000000000000000000000000103;
bytes32 private constant TEST_RUNTIME_ID =
0x8000000000000000000000000000000000000000000000000000000000000000;
string private constant CONSENSUS_ROUND_ROOT = "consensus.RoundRoot";

uint8 private constant ROOT_ROUND_KIND_STATE = 1;

address private constant SUBCALL =
0x0100000000000000000000000000000000000103;

error SubcallFailed(uint64 code, bytes module);

function test(bytes calldata method, bytes calldata body) public payable returns (bytes memory) {
(bool success, bytes memory data) = SUBCALL.call(abi.encode(method, body));
function test(
bytes calldata method,
bytes calldata body
) public payable returns (bytes memory) {
(bool success, bytes memory data) = SUBCALL.call(
abi.encode(method, body)
);
require(success, "subcall failed");
return decodeResponse(data);
}

function test_delegatecall(bytes calldata method, bytes calldata body) public returns (bytes memory) {
(bool success, bytes memory data) = SUBCALL.delegatecall(abi.encode(method, body));
function test_delegatecall(
bytes calldata method,
bytes calldata body
) public returns (bytes memory) {
(bool success, bytes memory data) = SUBCALL.delegatecall(
abi.encode(method, body)
);
require(success, "subcall failed");
return data;
}

function test_spin(bytes calldata method, bytes calldata body) public returns (bytes memory) {
(bool success, bytes memory data) = SUBCALL.call(abi.encode(method, body));
function test_spin(
bytes calldata method,
bytes calldata body
) public returns (bytes memory) {
(bool success, bytes memory data) = SUBCALL.call(
abi.encode(method, body)
);
require(success, "subcall failed");
for (int i = 0; i < 100; i++) {
// Spin.
}
return data;
}

function decodeResponse(bytes memory raw) internal pure returns (bytes memory) {
(uint64 status_code, bytes memory data) = abi.decode(raw, (uint64, bytes));
function test_consensus_round_root() public returns (bytes memory) {
(bool success, bytes memory data) = SUBCALL.call(
abi.encode(
CONSENSUS_ROUND_ROOT,
abi.encodePacked(
hex"a3",
hex"64",
"kind",
ROOT_ROUND_KIND_STATE, // Only works for values <= 23.
hex"65",
"round",
uint8(2), // Only works for values <= 23.
hex"6a",
"runtime_id",
hex"58",
hex"20",
TEST_RUNTIME_ID
)
)
);
require(success, "consensus round root subcall failed");
(uint64 status, bytes memory result) = abi.decode(
data,
(uint64, bytes)
);
if (status != 0) {
revert SubcallFailed(status, result);
}
return result;
}

function decodeResponse(
bytes memory raw
) internal pure returns (bytes memory) {
(uint64 status_code, bytes memory data) = abi.decode(
raw,
(uint64, bytes)
);

if (status_code != 0) {
revert SubcallFailed(status_code, data);
Expand Down
Loading