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

Economic Protocol scenario 3 - "contract earns fee" #1735

Merged
merged 27 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
678f34a
charlie-contract: initial check-in
miloszm Apr 9, 2024
9628bd8
contracts: added charlie contract
miloszm Apr 9, 2024
dbfdad9
rusk: passing economic mode
miloszm Apr 9, 2024
cfa2eaf
transfer-contract: EP scenario 3 implementation and test
miloszm Apr 9, 2024
9f0379a
rusk-recovery: enriched deploy method
miloszm Apr 9, 2024
2e76b99
charlie-contract: obtaining gas price from transfer contract
miloszm May 9, 2024
437c83d
rusk-abi: upgraded piecrust dependencies
miloszm May 9, 2024
64860f4
transfer-types: added types for economic events
miloszm May 14, 2024
677a39d
transfer-contract: optionality of gas_price, comments
miloszm May 16, 2024
d619323
node-data: added field in spent transaction
miloszm May 20, 2024
57822d6
node: added field in spent transaction
miloszm May 20, 2024
ea935f7
transfer-contract: moved applying economic mode to refund
miloszm May 20, 2024
30a4a95
stake-contract: moved applying economic mode to refund
miloszm May 20, 2024
bf077c1
charlie-contract: ininital check-in
miloszm Jun 3, 2024
ce68ce0
rusk: added charlie-contract
miloszm Jun 3, 2024
afa709f
contracts: added charlie-contract
miloszm Jun 3, 2024
23fc043
transfer-contract: economic mode support
miloszm Jun 3, 2024
2434539
stake-contract: economic mode support
miloszm Jun 3, 2024
96b7c85
execution-core: added economic events
miloszm Jun 3, 2024
f55a28b
node-data: economic mode support
miloszm Jun 3, 2024
561ec84
node: economic mode support
miloszm Jun 3, 2024
fc70c85
rusk-abi: economic mode support
miloszm Jun 3, 2024
ef159a5
rusk-recovery: enriched deploy with closure
miloszm Jun 3, 2024
d4cfe74
rusk: economic mode support
miloszm Jun 3, 2024
71288c4
Merge branch 'issue-1630-rebase-2' into issue-1630-contract-earns-fee
miloszm Jun 3, 2024
095ca59
rusk-recovery: rebase correction
miloszm Jun 3, 2024
d31bf5e
transfer-contract: rebase correction
miloszm Jun 3, 2024
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
# Test contracts
"contracts/alice",
"contracts/bob",
"contracts/charlie",
"contracts/host_fn",

# Genesis contracts
Expand Down
2 changes: 1 addition & 1 deletion contracts/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
SUBDIRS := alice bob license transfer stake host_fn
SUBDIRS := alice bob charlie license transfer stake host_fn

all: $(SUBDIRS) ## Build all the contracts

Expand Down
15 changes: 15 additions & 0 deletions contracts/charlie/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "charlie"
version = "0.3.0"
edition = "2021"
resolver = "2"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
execution-core = { version = "0.1.0", path = "../../execution-core" }
rusk-abi = { version = "0.13.0-rc", path = "../../rusk-abi", features = ["dlmalloc"] }
rkyv = { version = "0.7", default-features = false, features = ["size_32"] }
bytecheck = { version = "0.6", default-features = false }
dusk-bytes = "0.1"
18 changes: 18 additions & 0 deletions contracts/charlie/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
TARGET_DIR:="../../target/dusk"

all: wasm

wasm: ## Generate the optimized WASM for the contract given
@RUSTFLAGS="$(RUSTFLAGS) --remap-path-prefix $(HOME)= -C link-args=-zstack-size=65536" \
CARGO_TARGET_DIR=$(TARGET_DIR) \
cargo +dusk build \
--release \
--color=always \
-Z build-std=core,alloc,panic_abort \
-Z build-std-features=panic_immediate_abort \
--target wasm32-unknown-unknown
clippy:

test:

.PHONY: all test wasm
63 changes: 63 additions & 0 deletions contracts/charlie/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

#![no_std]
#![feature(arbitrary_self_types)]

extern crate alloc;

mod state;
use state::Charlie;

#[cfg(target_family = "wasm")]
#[path = ""]
mod wasm {
use super::*;

use rusk_abi::{ContractId, PaymentInfo};

#[no_mangle]
static SELF_ID: ContractId = ContractId::uninitialized();

static mut STATE: Charlie = Charlie;

#[no_mangle]
unsafe fn pay(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |()| STATE.pay())
}

#[no_mangle]
unsafe fn pay_and_fail(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |()| STATE.pay_and_fail())
}

#[no_mangle]
unsafe fn earn(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |()| STATE.earn())
}

#[no_mangle]
unsafe fn earn_and_fail(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |()| STATE.earn_and_fail())
}

#[no_mangle]
unsafe fn earn_indirectly_and_fail(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |()| STATE.earn_indirectly_and_fail())
}

#[no_mangle]
unsafe fn subsidize(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |arg| STATE.subsidize(arg))
}

const PAYMENT_INFO: PaymentInfo = PaymentInfo::Any(None);

#[no_mangle]
fn payment_info(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |_: ()| PAYMENT_INFO)
}
}
130 changes: 130 additions & 0 deletions contracts/charlie/src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use alloc::vec::Vec;
use dusk_bytes::Serializable;
use execution_core::transfer::Stct;
use execution_core::{BlsPublicKey, BlsSignature};
use rkyv::{Archive, Deserialize, Serialize};
use rusk_abi::TRANSFER_CONTRACT;

#[derive(Debug, Clone)]
pub struct Charlie;

/// Subsidy a contract with a value.
#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
#[archive_attr(derive(bytecheck::CheckBytes))]
pub struct Subsidy {
/// Public key to which the subsidy will belong.
pub public_key: BlsPublicKey,
/// Signature belonging to the given public key.
pub signature: BlsSignature,
/// Value of the subsidy.
pub value: u64,
/// Proof of the `STCT` circuit.
pub proof: Vec<u8>,
}

const SUBSIDY_MESSAGE_SIZE: usize = u64::SIZE + u64::SIZE;

/// Return the digest to be signed in the `subsidize` function of a contract.
#[must_use]
pub fn subsidy_signature_message(
counter: u64,
value: u64,
) -> [u8; SUBSIDY_MESSAGE_SIZE] {
let mut bytes = [0u8; SUBSIDY_MESSAGE_SIZE];

bytes[..u64::SIZE].copy_from_slice(&counter.to_bytes());
bytes[u64::SIZE..].copy_from_slice(&value.to_bytes());

bytes
}

impl Charlie {
fn gas_price() -> u64 {
rusk_abi::call::<(), u64>(TRANSFER_CONTRACT, "gas_price", &())
.expect("Obtaining gas price should succeed")
}

/// calling this method will be paid by the contract
pub fn pay(&mut self) {
const ALLOWANCE: u64 = 40_000_000;
let allowance = ALLOWANCE / Self::gas_price();
// this call is paid for by the contract, up to 'allowance'
rusk_abi::set_allowance(allowance);
}

/// calling this method should be paid by the contract, yet it
/// sets the allowance to a value too small to cover
/// the execution cost, transaction will fail
/// and contract balance won't be affected
pub fn pay_and_fail(&mut self) {
const ALLOWANCE: u64 = 8_000_000;
let allowance = ALLOWANCE / Self::gas_price();
// this call is paid for by the contract, up to 'allowance'
rusk_abi::set_allowance(allowance);
}

/// calling this method will cause the transaction fee to be
/// increased so that contract can earn the difference between
/// the contract's charge and the cost of gas actually spent
pub fn earn(&mut self) {
const CHARGE: u64 = 80_000_000;
let charge = CHARGE / Self::gas_price();
// charging 'charge' for the call
rusk_abi::set_charge(charge);
}

/// calling this method will cause the transaction fee to be
/// increased, yet its sets the charge to a value too small to cover
/// the actual execution cost, as a result the transaction will fail
/// and contract balance won't be affected
pub fn earn_and_fail(&mut self) {
const CHARGE: u64 = 8_000_000;
let charge = CHARGE / Self::gas_price();
// charging 'charge' for the call
rusk_abi::set_charge(charge);
}

/// this method calls the `earn` method indirectly, and in such case, since
/// charge is set by an indirectly called method, it won't have effect and
/// contract balance won't be affected
pub fn earn_indirectly_and_fail(&mut self) {
rusk_abi::call::<_, ()>(rusk_abi::self_id(), "earn", &())
.expect("earn call should succeed");
}

/// Subsidizes the contract with funds which can then be used
/// for sponsoring free uses of other methods of this contract.
/// Funds passed in this call will be used when granting allowances.
/// The subsidy operation is similar to staking, yet the funds
/// are deposited in this contract's "wallet".
pub fn subsidize(&mut self, subsidy: Subsidy) {
// verify the signature is over the correct digest
// note: counter is always zero - make sure that this is safe
let digest = subsidy_signature_message(0, subsidy.value).to_vec();

if !rusk_abi::verify_bls(digest, subsidy.public_key, subsidy.signature)
{
panic!("Invalid signature!");
}

// make call to transfer contract to transfer balance from the user to
// this contract
let transfer_module = TRANSFER_CONTRACT;

let stct = Stct {
module: rusk_abi::self_id().to_bytes(),
value: subsidy.value,
proof: subsidy.proof,
};

// subsidizing self with 'subsidy.value'
rusk_abi::call::<_, bool>(transfer_module, "stct", &stct)
.expect("Sending note to contract should succeed");
}
}
12 changes: 10 additions & 2 deletions contracts/stake/tests/common/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ use execution_core::{
transfer::{TreeLeaf, TRANSFER_TREE_DEPTH},
Note, Transaction, ViewKey,
};
use rusk_abi::{CallReceipt, ContractError, Error, Session, TRANSFER_CONTRACT};
use rusk_abi::{
CallReceipt, ContractError, ContractId, EconomicMode, Error, Session,
TRANSFER_CONTRACT,
};

const POINT_LIMIT: u64 = 0x100000000;

Expand Down Expand Up @@ -110,7 +113,12 @@ pub fn execute(
.call::<_, ()>(
TRANSFER_CONTRACT,
"refund",
&(tx.fee, receipt.gas_spent),
&(
tx.fee,
receipt.gas_spent,
EconomicMode::None,
None::<ContractId>,
),
u64::MAX,
)
.expect("Refunding must succeed");
Expand Down
7 changes: 7 additions & 0 deletions contracts/transfer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Added

- Added support for Economic Protocol scenario 3 [#1630]
- Added method which exposes the current gas price [#1604]

### Changed

- Change dependencies declarations enforce bytecheck [#1371]
Expand All @@ -17,5 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [0.7.0] - 2023-12-15

[#1630]: https://github.com/dusk-network/rusk/issues/1630
[#1604]: https://github.com/dusk-network/rusk/issues/1604
[#1675]: https://github.com/dusk-network/rusk/issues/1675
[#1371]: https://github.com/dusk-network/rusk/issues/1371
1 change: 1 addition & 0 deletions contracts/transfer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ rusk-profile = { version = "0.6", path = "../../rusk-profile" }
rusk-abi = { version = "0.13.0-rc", path = "../../rusk-abi", default-features = false, features = ["host"] }
transfer-circuits = { version = "0.5", path = "../../circuits/transfer" }
rkyv = { version = "0.7", default-features = false, features = ["size_32"] }
bytecheck = { version = "0.6", default-features = false }
hex = "0.4"
rand = "0.8"
ff = { version = "0.13", default-features = false }
Expand Down
16 changes: 12 additions & 4 deletions contracts/transfer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ unsafe fn num_notes(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |_: ()| STATE.num_notes())
}

#[no_mangle]
unsafe fn gas_price(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |_: ()| STATE.gas_price())
}

// "Feeder" queries

#[no_mangle]
Expand All @@ -109,10 +114,13 @@ unsafe fn spend_and_execute(arg_len: u32) -> u32 {

#[no_mangle]
unsafe fn refund(arg_len: u32) -> u32 {
rusk_abi::wrap_call(arg_len, |(fee, gas_spent)| {
assert_external_caller();
STATE.refund(fee, gas_spent)
})
rusk_abi::wrap_call(
arg_len,
|(fee, gas_spent, economic_mode, contract_id)| {
assert_external_caller();
STATE.refund(fee, gas_spent, economic_mode, contract_id)
},
)
}

#[no_mangle]
Expand Down
Loading
Loading