diff --git a/client-sdk/go/modules/rofl/rofl.go b/client-sdk/go/modules/rofl/rofl.go index 020ebc0b02..2aca248c90 100644 --- a/client-sdk/go/modules/rofl/rofl.go +++ b/client-sdk/go/modules/rofl/rofl.go @@ -18,10 +18,11 @@ var ( methodRegister = types.NewMethodName("rofl.Register", Register{}) // Queries. - methodApp = types.NewMethodName("rofl.App", AppQuery{}) - methodAppInstance = types.NewMethodName("rofl.AppInstance", AppInstanceQuery{}) - methodAppInstances = types.NewMethodName("rofl.AppInstances", AppQuery{}) - methodParameters = types.NewMethodName("rofl.Parameters", nil) + methodApp = types.NewMethodName("rofl.App", AppQuery{}) + methodAppInstance = types.NewMethodName("rofl.AppInstance", AppInstanceQuery{}) + methodAppInstances = types.NewMethodName("rofl.AppInstances", AppQuery{}) + methodParameters = types.NewMethodName("rofl.Parameters", nil) + methodStakeThresholds = types.NewMethodName("rofl.StakeThresholds", nil) ) // V1 is the v1 rofl module interface. @@ -46,6 +47,9 @@ type V1 interface { // AppInstances queries the registered instances of the given application. AppInstances(ctx context.Context, round uint64, id AppID) ([]*Registration, error) + // StakeThresholds queries the stake information for managing ROFL. + StakeThresholds(ctx context.Context, round uint64) (*StakeThresholds, error) + // Parameters queries the module parameters. Parameters(ctx context.Context, round uint64) (*Parameters, error) @@ -110,6 +114,16 @@ func (a *v1) AppInstances(ctx context.Context, round uint64, id AppID) ([]*Regis return instances, nil } +// Implements V1. +func (a *v1) StakeThresholds(ctx context.Context, round uint64) (*StakeThresholds, error) { + var thresholds StakeThresholds + err := a.rc.Query(ctx, round, methodStakeThresholds, nil, &thresholds) + if err != nil { + return nil, err + } + return &thresholds, nil +} + // Implements V1. func (a *v1) Parameters(ctx context.Context, round uint64) (*Parameters, error) { var params Parameters diff --git a/client-sdk/go/modules/rofl/types.go b/client-sdk/go/modules/rofl/types.go index 1e38bc8069..a406e7fef1 100644 --- a/client-sdk/go/modules/rofl/types.go +++ b/client-sdk/go/modules/rofl/types.go @@ -136,3 +136,8 @@ type Event struct { AppUpdated *AppUpdatedEvent AppRemoved *AppRemovedEvent } + +// StakeThresholds contains staking thresholds for managing ROFL. +type StakeThresholds struct { + AppCreate *types.BaseUnits `json:"app_create"` +} diff --git a/runtime-sdk/src/modules/rofl/config.rs b/runtime-sdk/src/modules/rofl/config.rs index 7a44a69a01..407b50fffc 100644 --- a/runtime-sdk/src/modules/rofl/config.rs +++ b/runtime-sdk/src/modules/rofl/config.rs @@ -16,6 +16,8 @@ pub trait Config: 'static { const GAS_COST_CALL_AUTHORIZED_ORIGIN_NODE: u64 = 2000; /// Gas cost of rofl.AuthorizedOriginEntity call. const GAS_COST_CALL_AUTHORIZED_ORIGIN_ENTITY: u64 = 2000; + /// Gas cost of rofl.StakeThresholds call. + const GAS_COST_CALL_STAKE_THRESHOLDS: u64 = 10; /// Amount of stake required for maintaining an application. /// diff --git a/runtime-sdk/src/modules/rofl/mod.rs b/runtime-sdk/src/modules/rofl/mod.rs index 90d4bc2434..7410044540 100644 --- a/runtime-sdk/src/modules/rofl/mod.rs +++ b/runtime-sdk/src/modules/rofl/mod.rs @@ -492,6 +492,29 @@ impl Module { Self::get_instances(args.id) } + /// Returns the minimum stake thresholds for managing ROFL. + #[handler(query = "rofl.StakeThresholds")] + fn query_stake_thresholds( + _ctx: &C, + _args: (), + ) -> Result { + Ok(types::StakeThresholds { + app_create: Cfg::STAKE_APP_CREATE, + }) + } + + /// Returns the minimum stake thresholds for managing ROFL. + #[handler(call = "rofl.StakeThresholds", internal)] + fn internal_query_stake_thresholds( + ctx: &C, + _args: (), + ) -> Result { + ::Core::use_tx_gas(Cfg::GAS_COST_CALL_STAKE_THRESHOLDS)?; + Ok(types::StakeThresholds { + app_create: Cfg::STAKE_APP_CREATE, + }) + } + fn resolve_payer_from_tx( ctx: &C, tx: &Transaction, diff --git a/runtime-sdk/src/modules/rofl/types.rs b/runtime-sdk/src/modules/rofl/types.rs index db4cf8dc0b..de79b9ca02 100644 --- a/runtime-sdk/src/modules/rofl/types.rs +++ b/runtime-sdk/src/modules/rofl/types.rs @@ -109,3 +109,10 @@ pub struct AppInstanceQuery { /// Runtime Attestation Key. pub rak: PublicKey, } + +/// Stake thresholds for managing ROFL. +#[derive(Clone, Debug, Default, cbor::Encode, cbor::Decode)] +pub struct StakeThresholds { + /// Required stake for creating new ROFL application. + pub app_create: token::BaseUnits, +} diff --git a/tests/e2e/rofl/tests.go b/tests/e2e/rofl/tests.go index 410b28b179..29e87644b0 100644 --- a/tests/e2e/rofl/tests.go +++ b/tests/e2e/rofl/tests.go @@ -5,6 +5,8 @@ import ( "fmt" "reflect" + "github.com/oasisprotocol/oasis-core/go/common/quantity" + "github.com/oasisprotocol/oasis-sdk/client-sdk/go/client" "github.com/oasisprotocol/oasis-sdk/client-sdk/go/crypto/signature/ed25519" "github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/accounts" @@ -105,6 +107,19 @@ func CreateUpdateRemoveTest(ctx context.Context, env *scenario.Env) error { func QueryTest(ctx context.Context, env *scenario.Env) error { rf := rofl.NewV1(env.Client) + // Query for stake thresholds. + s, err := rf.StakeThresholds(ctx, client.RoundLatest) + if err != nil { + return err + } + expected := types.BaseUnits{ + Amount: *quantity.NewFromUint64(1_000), + Denomination: types.NativeDenomination, + } + if s.AppCreate.String() != expected.String() { + return fmt.Errorf("expected stake threshold app create '%s', got '%s'", expected, s.AppCreate) + } + // Derive the AppID for the example oracle ROFL application that is registered in genesis. exampleAppID := rofl.NewAppIDGlobalName("example") diff --git a/tests/runtimes/components-ronl/src/lib.rs b/tests/runtimes/components-ronl/src/lib.rs index 74c58f01f4..b147be1a3b 100644 --- a/tests/runtimes/components-ronl/src/lib.rs +++ b/tests/runtimes/components-ronl/src/lib.rs @@ -4,7 +4,10 @@ use std::collections::BTreeMap; use once_cell::sync::Lazy; use oasis_runtime_sdk::{ - self as sdk, config, modules, modules::rofl::app_id::AppId, types::token::Denomination, Version, + self as sdk, config, modules, + modules::rofl::app_id::AppId, + types::token::{BaseUnits, Denomination}, + Version, }; pub mod oracle; @@ -20,7 +23,10 @@ pub static EXAMPLE_APP_ID: Lazy = Lazy::new(|| AppId::from_global_name("e impl modules::core::Config for Config {} -impl modules::rofl::Config for Config {} +impl modules::rofl::Config for Config { + /// Stake for creating a ROFL application. + const STAKE_APP_CREATE: BaseUnits = BaseUnits::new(1_000, Denomination::NATIVE); +} impl oracle::Config for Config { type Rofl = modules::rofl::Module;