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

PassAll gas option for program to program calls #1417

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
14 changes: 10 additions & 4 deletions x/programs/runtime/import_program.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,19 @@ func NewProgramModule(r *WasmRuntime) *ImportModule {
"call_program": {FuelCost: callProgramCost, Function: Function[callProgramInput, Result[RawBytes, ProgramCallErrorCode]](func(callInfo *CallInfo, input callProgramInput) (Result[RawBytes, ProgramCallErrorCode], error) {
newInfo := *callInfo

if err := callInfo.ConsumeFuel(input.Fuel); err != nil {
return Err[RawBytes, ProgramCallErrorCode](OutOfFuel), nil //nolint:nilerr
if input.Fuel == 0 {
newInfo.Fuel = callInfo.RemainingFuel()
} else {
if err := callInfo.ConsumeFuel(input.Fuel); err != nil {
return Err[RawBytes, ProgramCallErrorCode](OutOfFuel), nil //nolint:nilerr
}
newInfo.Fuel = input.Fuel
}

newInfo.Actor = callInfo.Program
newInfo.Program = input.Program
newInfo.FunctionName = input.FunctionName
newInfo.Params = input.Params
newInfo.Fuel = input.Fuel
newInfo.Value = input.Value

result, err := r.CallProgram(
Expand All @@ -87,7 +91,9 @@ func NewProgramModule(r *WasmRuntime) *ImportModule {
}

// return any remaining fuel to the calling program
callInfo.AddFuel(newInfo.RemainingFuel())
if callInfo.Fuel > 0 {
callInfo.AddFuel(newInfo.RemainingFuel())
}

return Ok[RawBytes, ProgramCallErrorCode](result), nil
})},
Expand Down
24 changes: 24 additions & 0 deletions x/programs/runtime/import_program_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,30 @@ func TestImportProgramCallProgramWithParam(t *testing.T) {
require.Equal(expected, result)
}

func TestImportProgramCallProgramWithParamPassAllGas(t *testing.T) {
require := require.New(t)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

program := newTestProgram(ctx, "call_program")

expected, err := Serialize(uint64(1))
require.NoError(err)

result, err := program.Call(
"call_with_param",
uint64(1))
require.NoError(err)
require.Equal(expected, result)

result, err = program.Call(
"call_with_param_external",
program.Address, uint64(0), uint64(1))
require.NoError(err)
require.Equal(expected, result)
}

func TestImportProgramCallProgramWithParams(t *testing.T) {
require := require.New(t)

Expand Down
11 changes: 5 additions & 6 deletions x/programs/rust/examples/automated-market-maker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ state_schema! {
LiquidityToken => Program,
}

const MAX_GAS: Gas = 10000000;

/// Initializes the pool with the two tokens and the liquidity token
#[public]
pub fn init(context: &mut Context, token_x: Program, token_y: Program, liquidity_token: Id) {
let lt_program = context.deploy(liquidity_token, &[0, 1]);
let liquidity_context = ExternalCallContext::new(lt_program, MAX_GAS, 0);
let liquidity_context = ExternalCallContext::new(lt_program, Gas::PassAll, 0);
token::init(
&liquidity_context,
String::from("liquidity token"),
Expand Down Expand Up @@ -208,20 +206,21 @@ fn token_programs(context: &mut Context) -> (Program, Program) {
.expect("token y not initialized"),
)
}

/// Returns the external call contexts for the tokens in the pool
fn external_token_contracts(context: &mut Context) -> (ExternalCallContext, ExternalCallContext) {
let (token_x, token_y) = token_programs(context);

(
ExternalCallContext::new(token_x, MAX_GAS, 0),
ExternalCallContext::new(token_y, MAX_GAS, 0),
ExternalCallContext::new(token_x, Gas::PassAll, 0),
ExternalCallContext::new(token_y, Gas::PassAll, 0),
)
}

/// Returns the external call context for the liquidity token
fn external_liquidity_token(context: &mut Context) -> ExternalCallContext {
let token = context.get(LiquidityToken).unwrap().unwrap();
ExternalCallContext::new(token, MAX_GAS, 0)
ExternalCallContext::new(token, Gas::PassAll, 0)
}

mod internal {
Expand Down
4 changes: 2 additions & 2 deletions x/programs/rust/examples/counter-external/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use wasmlanche_sdk::{public, Address, Context, ExternalCallContext, Program};

#[public]
pub fn inc(_: &mut Context, external: Program, address: Address) {
let ctx = ExternalCallContext::new(external, 1_000_000, 0);
let ctx = ExternalCallContext::new(external, 1_000_000.into(), 0);
counter::inc(&ctx, address, 1);
}

#[public]
pub fn get_value(_: &mut Context, external: Program, address: Address) -> u64 {
let ctx = ExternalCallContext::new(external, 1_000_000, 0);
let ctx = ExternalCallContext::new(external, 1_000_000.into(), 0);
counter::get_value(&ctx, address)
}

Expand Down
4 changes: 2 additions & 2 deletions x/programs/rust/wasmlanche-sdk/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ impl ExternalCallContext {
}

#[must_use]
pub fn max_units(&self) -> Gas {
self.max_units
pub fn max_units(&self) -> &Gas {
&self.max_units
}

#[must_use]
Expand Down
15 changes: 10 additions & 5 deletions x/programs/rust/wasmlanche-sdk/src/program.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

use crate::{memory::HostPtr, types::Address, Gas};
use crate::{
memory::HostPtr,
types::{Address, Gas},
};
use borsh::{BorshDeserialize, BorshSerialize};
use thiserror::Error;

Expand Down Expand Up @@ -63,23 +66,23 @@ impl Program {
/// The caller must ensure that `function_name` + `args` point to valid memory locations.
/// # Examples
/// ```no_run
/// # use wasmlanche_sdk::{Address, Program};
/// # use wasmlanche_sdk::{Address, Program, Gas};
/// #
/// # let program_id = [0; Address::LEN];
/// # let target: Program = borsh::from_slice(&program_id).unwrap();
/// let increment = 10;
/// let params = borsh::to_vec(&increment).unwrap();
/// let max_units = 1000000;
/// let value = 0;
/// let has_incremented: bool = target.call_function("increment", &params, max_units, value)?;
/// let has_incremented: bool = target.call_function("increment", &params, &Gas::PassAll, value)?;
/// assert!(has_incremented);
/// # Ok::<(), wasmlanche_sdk::ExternalCallError>(())
/// ```
pub fn call_function<T: BorshDeserialize>(
&self,
function_name: &str,
args: &[u8],
max_units: Gas,
max_units: &Gas,
max_value: u64,
) -> Result<T, ExternalCallError> {
#[link(wasm_import_module = "program")]
Expand All @@ -88,6 +91,8 @@ impl Program {
fn call_program(ptr: *const u8, len: usize) -> HostPtr;
}

let max_units = &max_units.into();

let args = CallProgramArgs {
target: self,
function: function_name.as_bytes(),
Expand Down Expand Up @@ -125,6 +130,6 @@ struct CallProgramArgs<'a> {
target: &'a Program,
function: &'a [u8],
args: &'a [u8],
max_units: Gas,
max_units: &'a u64,
max_value: u64,
}
35 changes: 32 additions & 3 deletions x/programs/rust/wasmlanche-sdk/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,46 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

use std::mem::size_of;

use borsh::{BorshDeserialize, BorshSerialize};
use bytemuck::{Pod, Zeroable};
use std::mem::size_of;
use std::num::NonZeroU64;

/// Byte length of an action ID.
pub const ID_LEN: usize = 32;
/// Action id.
pub type Id = [u8; ID_LEN];

/// Gas type alias.
pub type Gas = u64;
pub enum Gas {
PassAll,
Units(NonZeroU64),
}

impl From<&Gas> for u64 {
fn from(value: &Gas) -> Self {
match value {
Gas::PassAll => 0,
Gas::Units(num) => num.get(),
}
}
}

impl From<u64> for Gas {
fn from(value: u64) -> Self {
match value {
0 => Gas::PassAll,
num => Gas::Units(unsafe { NonZeroU64::new_unchecked(num) }),
}
}
}

impl BorshDeserialize for Gas {
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
let num = u64::deserialize_reader(reader)?;
Ok(num.into())
}
}

/// A newtype wrapper around address bytes.
#[cfg_attr(feature = "debug", derive(Debug))]
Expand Down
2 changes: 1 addition & 1 deletion x/programs/test/programs/balance/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ pub fn send_balance(_: &mut Context, recipient: Address) -> bool {
#[public]
pub fn send_via_call(_: &mut Context, target: Program, max_units: Gas, value: u64) -> u64 {
target
.call_function("balance", &[], max_units, value)
.call_function("balance", &[], &max_units, value)
.unwrap()
}
8 changes: 4 additions & 4 deletions x/programs/test/programs/call_program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub fn simple_call(_: &mut Context) -> i64 {
#[public]
pub fn simple_call_external(_: &mut Context, target: Program, max_units: Gas) -> i64 {
target
.call_function("simple_call", &[], max_units, 0)
.call_function("simple_call", &[], &max_units, 0)
.unwrap()
}

Expand All @@ -23,7 +23,7 @@ pub fn actor_check(context: &mut Context) -> Address {
#[public]
pub fn actor_check_external(_: &mut Context, target: Program, max_units: Gas) -> Address {
target
.call_function("actor_check", &[], max_units, 0)
.call_function("actor_check", &[], &max_units, 0)
.expect("failure")
}

Expand All @@ -40,7 +40,7 @@ pub fn call_with_param_external(
value: i64,
) -> i64 {
target
.call_function("call_with_param", &value.to_le_bytes(), max_units, 0)
.call_function("call_with_param", &value.to_le_bytes(), &max_units, 0)
.unwrap()
}

Expand All @@ -63,6 +63,6 @@ pub fn call_with_two_params_external(
.chain(value2.to_le_bytes())
.collect();
target
.call_function("call_with_two_params", &args, max_units, 0)
.call_function("call_with_two_params", &args, &max_units, 0)
.unwrap()
}
2 changes: 1 addition & 1 deletion x/programs/test/programs/fuel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ pub fn get_fuel(ctx: &mut Context) -> u64 {
#[public]
pub fn out_of_fuel(_: &mut Context, target: Program) -> ExternalCallError {
target
.call_function::<u64>("get_fuel", &[], 0, 0)
.call_function::<u64>("get_fuel", &[], &1u64.into(), 0)
.unwrap_err()
}
4 changes: 2 additions & 2 deletions x/programs/test/programs/return_complex_type/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

use wasmlanche_sdk::{borsh::BorshSerialize, public, Address, Context, Gas};
use wasmlanche_sdk::{borsh::BorshSerialize, public, Address, Context};

#[derive(BorshSerialize)]
#[borsh(crate = "wasmlanche_sdk::borsh")]
pub struct ComplexReturn {
account: Address,
max_units: Gas,
max_units: u64,
}

#[public]
Expand Down
Loading