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

Burn functionality #4573

Merged
merged 30 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d30a282
wip: first impletation of burn
hoffmannjan Feb 7, 2024
5b67986
feat: burn methods exposed
hoffmannjan Feb 7, 2024
01a3ef4
config: added default value for burn method
hoffmannjan Feb 8, 2024
9137040
added prod chainspec value
hoffmannjan Feb 13, 2024
0cab199
added test contract
hoffmannjan Feb 13, 2024
c02fb70
WIP: Added test boilerplate
hoffmannjan Feb 13, 2024
e018267
added reduce_total_supply_unchecked
hoffmannjan Feb 15, 2024
7561f66
added auth test
hoffmannjan Feb 15, 2024
6723271
fixed warnings
hoffmannjan Feb 20, 2024
b9c6596
code formatted
hoffmannjan Feb 20, 2024
18d538f
new implementation whith permission checks
hoffmannjan Feb 27, 2024
31ac2cd
Reimplemented burn method
hoffmannjan Feb 28, 2024
4deb7ec
first test scenerio implemented
hoffmannjan Feb 29, 2024
9f8cc0c
implemented should_not_burn_excess_tokens test
hoffmannjan Feb 29, 2024
353b70b
reimplemented client contract
hoffmannjan Feb 29, 2024
bb09705
fix deserialization error, add demo contract
igor-casper Feb 29, 2024
5b55aa1
fix warnings
hoffmannjan Feb 29, 2024
6972655
WIP
hoffmannjan Mar 5, 2024
43a3495
apply review suggestions
igor-casper Mar 5, 2024
9659031
applied fixes to burn contract
hoffmannjan Mar 5, 2024
2c59473
format fixes
hoffmannjan Mar 5, 2024
6173fff
Merge branch 'feat-1.6' into feat-burning
hoffmannjan Mar 5, 2024
6402d2f
apply clippy lints
hoffmannjan Mar 5, 2024
2bc09d6
applied fmt fixes
hoffmannjan Mar 5, 2024
f49269a
added requested changes
hoffmannjan Mar 5, 2024
631cd62
method better naming
hoffmannjan Mar 6, 2024
3898b2b
fix in node/src/components/network/tasks.rs
hoffmannjan Mar 12, 2024
74149a6
added audit ignore
hoffmannjan Mar 12, 2024
adc347c
fixed test
hoffmannjan Mar 12, 2024
4492011
fixed formatting
hoffmannjan Mar 12, 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
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 28 additions & 1 deletion execution_engine/src/core/runtime/mint_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
core::{engine_state::SystemContractRegistry, execution},
storage::global_state::StateReader,
system::mint::{
runtime_provider::RuntimeProvider, storage_provider::StorageProvider,
detail, runtime_provider::RuntimeProvider, storage_provider::StorageProvider,
system_provider::SystemProvider, Mint,
},
};
Expand Down Expand Up @@ -189,4 +189,31 @@ where
R: StateReader<Key, StoredValue>,
R::Error: Into<execution::Error>,
{
/// Burns native tokens.
fn burn(&mut self, purse: URef, amount: U512) -> Result<(), Error> {
hoffmannjan marked this conversation as resolved.
Show resolved Hide resolved
let purse_key = Key::URef(purse);
self.context
.validate_writeable(&purse_key)
.map_err(|_| Error::InvalidAccessRights)?;
self.context
.validate_key(&purse_key)
.map_err(|_| Error::InvalidURef)?;
EdHastingsCasperAssociation marked this conversation as resolved.
Show resolved Hide resolved

let source_balance: U512 = match self.read_balance(purse)? {
Some(source_balance) => source_balance,
None => return Err(Error::PurseNotFound),
};

let new_balance = match source_balance.checked_sub(amount) {
Some(value) => value,
None => U512::zero(),
hoffmannjan marked this conversation as resolved.
Show resolved Hide resolved
};

// source_balance is >= than new_balance
// this should block user from reducing totaly supply beyond what they own
let burned_amount = source_balance - new_balance;

self.write_balance(purse, new_balance)?;
detail::reduce_total_supply_unchecked(self, burned_amount)
}
}
9 changes: 9 additions & 0 deletions execution_engine/src/core/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,15 @@ where
let result: Result<(), mint::Error> = mint_runtime.reduce_total_supply(amount);
CLValue::from_t(result).map_err(Self::reverter)
})(),
// Type: `fn burn(purse: URef, amount: U512)`
mint::METHOD_BURN => (|| {
mint_runtime.charge_system_contract_call(mint_costs.burn)?;

let purse: URef = Self::get_named_argument(runtime_args, mint::ARG_PURSE)?;
let amount: U512 = Self::get_named_argument(runtime_args, mint::ARG_AMOUNT)?;
let result = mint_runtime.burn(purse, amount).map_err(Self::reverter)?;
hoffmannjan marked this conversation as resolved.
Show resolved Hide resolved
CLValue::from_t(result).map_err(Self::reverter)
})(),
// Type: `fn create() -> URef`
mint::METHOD_CREATE => (|| {
mint_runtime.charge_system_contract_call(mint_costs.create)?;
Expand Down
4 changes: 2 additions & 2 deletions execution_engine/src/core/runtime_context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ where
}

/// Validates whether keys used in the `value` are not forged.
fn validate_value(&self, value: &StoredValue) -> Result<(), Error> {
pub fn validate_value(&self, value: &StoredValue) -> Result<(), Error> {
EdHastingsCasperAssociation marked this conversation as resolved.
Show resolved Hide resolved
match value {
StoredValue::CLValue(cl_value) => self.validate_cl_value(cl_value),
StoredValue::Account(account) => {
Expand Down Expand Up @@ -768,7 +768,7 @@ where
}

/// Validates if a [`Key`] refers to a [`URef`] and has a write bit set.
fn validate_writeable(&self, key: &Key) -> Result<(), Error> {
pub fn validate_writeable(&self, key: &Key) -> Result<(), Error> {
hoffmannjan marked this conversation as resolved.
Show resolved Hide resolved
if self.is_writeable(key) {
Ok(())
} else {
Expand Down
16 changes: 15 additions & 1 deletion execution_engine/src/shared/system_config/mint_costs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use serde::{Deserialize, Serialize};
pub const DEFAULT_MINT_COST: u32 = 2_500_000_000;
/// Default cost of the `reduce_total_supply` mint entry point.
pub const DEFAULT_REDUCE_TOTAL_SUPPLY_COST: u32 = 10_000;
/// Default cost of the `burn` mint entry point.
pub const DEFAULT_BURN_COST: u32 = 10_000;
/// Default cost of the `create` mint entry point.
pub const DEFAULT_CREATE_COST: u32 = 2_500_000_000;
/// Default cost of the `balance` mint entry point.
Expand All @@ -27,6 +29,8 @@ pub struct MintCosts {
pub mint: u32,
/// Cost of calling the `reduce_total_supply` entry point.
pub reduce_total_supply: u32,
/// Cost of calling the `burn` entry point.
pub burn: u32,
/// Cost of calling the `create` entry point.
pub create: u32,
/// Cost of calling the `balance` entry point.
Expand All @@ -44,6 +48,7 @@ impl Default for MintCosts {
Self {
mint: DEFAULT_MINT_COST,
reduce_total_supply: DEFAULT_REDUCE_TOTAL_SUPPLY_COST,
burn: DEFAULT_BURN_COST,
create: DEFAULT_CREATE_COST,
balance: DEFAULT_BALANCE_COST,
transfer: DEFAULT_TRANSFER_COST,
Expand All @@ -60,6 +65,7 @@ impl ToBytes for MintCosts {
let Self {
mint,
reduce_total_supply,
burn,
create,
balance,
transfer,
Expand All @@ -69,6 +75,7 @@ impl ToBytes for MintCosts {

ret.append(&mut mint.to_bytes()?);
ret.append(&mut reduce_total_supply.to_bytes()?);
ret.append(&mut burn.to_bytes()?);
EdHastingsCasperAssociation marked this conversation as resolved.
Show resolved Hide resolved
ret.append(&mut create.to_bytes()?);
ret.append(&mut balance.to_bytes()?);
ret.append(&mut transfer.to_bytes()?);
Expand All @@ -82,6 +89,7 @@ impl ToBytes for MintCosts {
let Self {
mint,
reduce_total_supply,
burn,
create,
balance,
transfer,
Expand All @@ -91,6 +99,7 @@ impl ToBytes for MintCosts {

mint.serialized_length()
+ reduce_total_supply.serialized_length()
+ burn.serialized_length()
+ create.serialized_length()
+ balance.serialized_length()
+ transfer.serialized_length()
Expand All @@ -102,7 +111,8 @@ impl ToBytes for MintCosts {
impl FromBytes for MintCosts {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), casper_types::bytesrepr::Error> {
let (mint, rem) = FromBytes::from_bytes(bytes)?;
let (reduce_total_supply, rem) = FromBytes::from_bytes(rem)?;
let (reduce_total_supply, _) = FromBytes::from_bytes(rem)?;
let (burn, rem) = FromBytes::from_bytes(bytes)?;
hoffmannjan marked this conversation as resolved.
Show resolved Hide resolved
let (create, rem) = FromBytes::from_bytes(rem)?;
let (balance, rem) = FromBytes::from_bytes(rem)?;
let (transfer, rem) = FromBytes::from_bytes(rem)?;
Expand All @@ -113,6 +123,7 @@ impl FromBytes for MintCosts {
Self {
mint,
reduce_total_supply,
burn,
create,
balance,
transfer,
Expand All @@ -128,6 +139,7 @@ impl Distribution<MintCosts> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> MintCosts {
MintCosts {
mint: rng.gen(),
burn: rng.gen(),
reduce_total_supply: rng.gen(),
create: rng.gen(),
balance: rng.gen(),
Expand All @@ -149,6 +161,7 @@ pub mod gens {
pub fn mint_costs_arb()(
mint in num::u32::ANY,
reduce_total_supply in num::u32::ANY,
burn in num::u32::ANY,
create in num::u32::ANY,
balance in num::u32::ANY,
transfer in num::u32::ANY,
Expand All @@ -158,6 +171,7 @@ pub mod gens {
MintCosts {
mint,
reduce_total_supply,
burn,
create,
balance,
transfer,
Expand Down
30 changes: 7 additions & 23 deletions execution_engine/src/system/mint.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub(crate) mod detail;
pub(crate) mod runtime_provider;
pub(crate) mod storage_provider;
pub(crate) mod system_provider;
Expand All @@ -15,6 +16,8 @@ use casper_types::{
Key, Phase, PublicKey, StoredValue, URef, U512,
};

use detail::reduce_total_supply_unchecked;

use crate::{
core::engine_state::SystemContractRegistry,
system::mint::{
Expand Down Expand Up @@ -54,6 +57,9 @@ pub trait Mint: RuntimeProvider + StorageProvider + SystemProvider {
Ok(purse_uref)
}

/// Burns native tokens.
fn burn(&mut self, purse: URef, amount: U512) -> Result<(), Error>;

/// Reduce total supply by `amount`. Returns unit on success, otherwise
/// an error.
fn reduce_total_supply(&mut self, amount: U512) -> Result<(), Error> {
Expand All @@ -63,29 +69,7 @@ pub trait Mint: RuntimeProvider + StorageProvider + SystemProvider {
return Err(Error::InvalidTotalSupplyReductionAttempt);
}

if amount.is_zero() {
return Ok(()); // no change to supply
}

// get total supply or error
let total_supply_uref = match self.get_key(TOTAL_SUPPLY_KEY) {
Some(Key::URef(uref)) => uref,
Some(_) => return Err(Error::MissingKey), // TODO
None => return Err(Error::MissingKey),
};
let total_supply: U512 = self
.read(total_supply_uref)?
.ok_or(Error::TotalSupplyNotFound)?;

// decrease total supply
let reduced_total_supply = total_supply
.checked_sub(amount)
.ok_or(Error::ArithmeticOverflow)?;

// update total supply
self.write(total_supply_uref, reduced_total_supply)?;

Ok(())
reduce_total_supply_unchecked(self, amount)
hoffmannjan marked this conversation as resolved.
Show resolved Hide resolved
}

/// Read balance of given `purse`.
Expand Down
39 changes: 39 additions & 0 deletions execution_engine/src/system/mint/detail.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use casper_types::{
system::{mint, mint::TOTAL_SUPPLY_KEY},
Key, U512,
};

use crate::system::mint::{runtime_provider::RuntimeProvider, storage_provider::StorageProvider};

// Please do not expose this to the user!
pub(crate) fn reduce_total_supply_unchecked<P>(
EdHastingsCasperAssociation marked this conversation as resolved.
Show resolved Hide resolved
auction: &mut P,
amount: U512,
) -> Result<(), mint::Error>
where
P: StorageProvider + RuntimeProvider + ?Sized,
{
if amount.is_zero() {
return Ok(()); // no change to supply
}

// get total supply or error
let total_supply_uref = match auction.get_key(TOTAL_SUPPLY_KEY) {
Some(Key::URef(uref)) => uref,
Some(_) => return Err(mint::Error::MissingKey), // TODO
None => return Err(mint::Error::MissingKey),
};
let total_supply: U512 = auction
.read(total_supply_uref)?
.ok_or(mint::Error::TotalSupplyNotFound)?;

// decrease total supply
let reduced_total_supply = total_supply
.checked_sub(amount)
.ok_or(mint::Error::ArithmeticOverflow)?;

// update total supply
auction.write(total_supply_uref, reduced_total_supply)?;

Ok(())
}
Loading
Loading