Struct concordium_smart_contract_testing::Chain
source · pub struct Chain {
pub accounts: BTreeMap<AccountAddressEq, Account>,
pub modules: BTreeMap<ModuleReference, ContractModule>,
pub contracts: BTreeMap<ContractAddress, Contract>,
/* private fields */
}
Expand description
Represents the blockchain and supports a number of operations, including creating accounts, deploying modules, initializing contract, updating contracts and invoking contracts.
Fields§
§accounts: BTreeMap<AccountAddressEq, Account>
Accounts and info about them.
This uses AccountAddressEq
to ensure that account aliases are seen
as one account.
modules: BTreeMap<ModuleReference, ContractModule>
Smart contract modules.
contracts: BTreeMap<ContractAddress, Contract>
Smart contract instances.
Implementations§
source§impl Chain
impl Chain
sourcepub fn builder() -> ChainBuilder
pub fn builder() -> ChainBuilder
Get a ChainBuilder
for constructing a new Chain
with a builder
pattern.
See the ChainBuilder
for more details.
sourcepub fn new_with_time_and_rates(
block_time: SlotTime,
micro_ccd_per_euro: ExchangeRate,
euro_per_energy: ExchangeRate
) -> Result<Self, ExchangeRateError>
pub fn new_with_time_and_rates( block_time: SlotTime, micro_ccd_per_euro: ExchangeRate, euro_per_energy: ExchangeRate ) -> Result<Self, ExchangeRateError>
Create a new Chain
where all the configurable parameters are
provided.
Returns an error if the exchange rates provided makes one energy cost
more than u64::MAX / 100_000_000_000
.
For more configuration options and flexibility, use the builder
pattern. See Chain::builder
.
sourcepub fn new_with_time(block_time: SlotTime) -> Self
pub fn new_with_time(block_time: SlotTime) -> Self
Create a new Chain
with a specified block_time
where
micro_ccd_per_euro
defaults to50000 / 1
euro_per_energy
defaults to1 / 50000
.
For more configuration options and flexibility, use the builder
pattern. See Chain::builder
.
sourcepub fn new() -> Self
pub fn new() -> Self
Create a new Chain
where
block_time
defaults to0
,micro_ccd_per_euro
defaults to50000 / 1
euro_per_energy
defaults to1 / 50000
.
With these exchange rates, one energy costs one microCCD.
For more configuration options and flexibility, use the builder
pattern. See Chain::builder
.
sourcepub fn calculate_energy_cost(&self, energy: Energy) -> Amount
pub fn calculate_energy_cost(&self, energy: Energy) -> Amount
Helper function for converting Energy
to Amount
using the two
ExchangeRate
s euro_per_energy
and micro_ccd_per_euro
.
sourcepub fn get_contract(&self, address: ContractAddress) -> Option<&Contract>
pub fn get_contract(&self, address: ContractAddress) -> Option<&Contract>
Get the state of the contract if it exists in the Chain
.
sourcepub fn get_module(&self, module: ModuleReference) -> Option<&ContractModule>
pub fn get_module(&self, module: ModuleReference) -> Option<&ContractModule>
Get the the module if it exists in the Chain
.
sourcepub fn get_account(&self, address: AccountAddress) -> Option<&Account>
pub fn get_account(&self, address: AccountAddress) -> Option<&Account>
Get the state of the account if it exists in the Chain
.
Account addresses that are aliases will return the same account.
sourcepub fn module_deploy_v1(
&mut self,
signer: Signer,
sender: AccountAddress,
wasm_module: WasmModule
) -> Result<ModuleDeploySuccess, ModuleDeployError>
pub fn module_deploy_v1( &mut self, signer: Signer, sender: AccountAddress, wasm_module: WasmModule ) -> Result<ModuleDeploySuccess, ModuleDeployError>
Deploy a smart contract module using the same validation rules as enforced by the node.
The WasmModule
can be loaded from disk with either
module_load_v1
or module_load_v1_raw
.
Parameters:
signer
: the signer with a number of keys, which affects the cost.sender
: the sender account.module
: the v1 wasm module.
sourcepub fn module_deploy_v1_debug(
&mut self,
signer: Signer,
sender: AccountAddress,
wasm_module: WasmModule,
enable_debug: bool
) -> Result<ModuleDeploySuccess, ModuleDeployError>
pub fn module_deploy_v1_debug( &mut self, signer: Signer, sender: AccountAddress, wasm_module: WasmModule, enable_debug: bool ) -> Result<ModuleDeploySuccess, ModuleDeployError>
Like module_deploy_v1
except that optionally debugging output may be allowed in the module.
sourcepub fn contract_init(
&mut self,
signer: Signer,
sender: AccountAddress,
energy_reserved: Energy,
payload: InitContractPayload
) -> Result<ContractInitSuccess, ContractInitError>
pub fn contract_init( &mut self, signer: Signer, sender: AccountAddress, energy_reserved: Energy, payload: InitContractPayload ) -> Result<ContractInitSuccess, ContractInitError>
Initialize a contract.
Parameters:
signer
: the signer with a number of keys, which affects the cost.sender
: The account paying for the transaction. Will also become the owner of the contract created.energy_reserved
: Amount of energy reserved for executing the init method.payload
:amount
: The initial balance of the contract. Subtracted from thesender
account.mod_ref
: The reference to the a module that has already been deployed.init_name
: Name of the contract to initialize.param
: Parameter provided to the init method.
sourcepub fn contract_update(
&mut self,
signer: Signer,
invoker: AccountAddress,
sender: Address,
energy_reserved: Energy,
payload: UpdateContractPayload
) -> Result<ContractInvokeSuccess, ContractInvokeError>
pub fn contract_update( &mut self, signer: Signer, invoker: AccountAddress, sender: Address, energy_reserved: Energy, payload: UpdateContractPayload ) -> Result<ContractInvokeSuccess, ContractInvokeError>
Update a contract by calling one of its entrypoints.
If successful, all changes will be saved.
Parameters:
signer
: aSigner
with a number of keys. The number of keys affects the cost of the transaction.invoker
: the account paying for the transaction.sender
: the sender of the message, can be an account or contract. For top-level invocations, such as those caused by sending a contract update transaction on the chain, thesender
is always theinvoker
. Here we provide extra freedom for testing invocations where the sender differs.energy_reserved
: the maximum energy that can be used in the update.payload
: The data detailing which contract and receive method to call etc.
sourcepub fn contract_invoke(
&self,
invoker: AccountAddress,
sender: Address,
energy_reserved: Energy,
payload: UpdateContractPayload
) -> Result<ContractInvokeSuccess, ContractInvokeError>
pub fn contract_invoke( &self, invoker: AccountAddress, sender: Address, energy_reserved: Energy, payload: UpdateContractPayload ) -> Result<ContractInvokeSuccess, ContractInvokeError>
Invoke a contract by calling an entrypoint.
Similar to Chain::contract_update
except that
all changes are discarded afterwards. Typically used for “view”
functions.
Parameters:
invoker
: the account used as invoker. Since this isn’t a transaction, it won’t be charged.sender
: the sender. Can be either a contract address or an account address.energy_reserved
: the maximum energy that can be used in the update.payload
: The data detailing which contract and receive method to call etc.
sourcepub fn contract_invoke_external(
&self,
sender: Option<ExternalAddress>,
energy_reserved: Energy,
payload: InvokeExternalContractPayload,
block: Option<BlockHash>
) -> Result<ContractInvokeExternalSuccess, ContractInvokeExternalError>
pub fn contract_invoke_external( &self, sender: Option<ExternalAddress>, energy_reserved: Energy, payload: InvokeExternalContractPayload, block: Option<BlockHash> ) -> Result<ContractInvokeExternalSuccess, ContractInvokeExternalError>
Invoke an external contract entrypoint.
Similar to Chain::contract_invoke
except that
it invokes/dry runs a contract on the external node.
Parameters:
invoker
: the account used as invoker.- The account must exist on the connected node.
sender
: the sender, can also be a contract.- The sender must exist on the connected node.
energy_reserved
: the maximum energy that can be used in the update.payload
: The data detailing which contract and receive method to call etc.block
: The block in which the invocation will be simulated, as if it was at the end of the block. IfNone
is provided, theexternal_query_block
is used instead.
§Example:
let mut chain = Chain::builder()
.external_node_connection(Endpoint::from_static("http://node.testnet.concordium.com:20000"))
.build()
.unwrap();
// Set up an external contract.
let external_contract =
chain.add_external_contract(ContractAddress::new(1010, 0)).unwrap();
// Set up an external account.
let external_acc =
chain.add_external_account("
3U4sfVSqGG6XK8g6eho2qRYtnHc4MWJBG1dfxdtPGbfHwFxini".parse().unwrap()).
unwrap();
let res = chain.contract_invoke_external(
Some(ExternalAddress::Account(external_acc)),
10000.into(),
InvokeExternalContractPayload {
amount: Amount::zero(),
address: external_contract,
receive_name:
OwnedReceiveName::new_unchecked("my_contract.view".to_string()),
message: OwnedParameter::empty(),
},
None,
);
sourcepub fn create_account(&mut self, account: Account) -> Option<Account>
pub fn create_account(&mut self, account: Account) -> Option<Account>
Create an account.
If an account with a matching address already exists this method will replace it and return the old account.
Note that if the first 29-bytes of an account are identical, then they are considered aliases on each other in all methods. See the example below:
let mut chain = Chain::new();
let acc = AccountAddress([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
]);
let acc_alias = AccountAddress([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
2, 3, // Only last three bytes differ.
]);
chain.create_account(Account::new(acc, Amount::from_ccd(123)));
assert_eq!(
chain.account_balance_available(acc_alias), // Using the alias for lookup.
Some(Amount::from_ccd(123))
);
sourcepub fn add_external_account(
&mut self,
address: AccountAddress
) -> Result<ExternalAccountAddress, ExternalNodeError>
pub fn add_external_account( &mut self, address: AccountAddress ) -> Result<ExternalAccountAddress, ExternalNodeError>
Add an external account from a connected external node.
If the account exists on the external node at the time of the
external_query_block
, then an ExternalAccountAddress
is returned.
The address can be used with Chain::contract_invoke_external
.
Otherwise, an error is returned.
Barring external node errors, the method is idempotent, and so it can be called multiple times with the same effect.
sourcepub fn add_external_contract(
&mut self,
address: ContractAddress
) -> Result<ExternalContractAddress, ExternalNodeError>
pub fn add_external_contract( &mut self, address: ContractAddress ) -> Result<ExternalContractAddress, ExternalNodeError>
Add an external contract from a connected external node.
If the contract exists on the external node at the time of the
external_query_block
, then an ExternalContractAddress
is returned.
The address can be used with Chain::contract_invoke_external
.
Otherwise, an error is returned.
Barring external node errors, the method is idempotent, and so it can be called multiple times with the same effect.
sourcepub fn account_balance(&self, address: AccountAddress) -> Option<AccountBalance>
pub fn account_balance(&self, address: AccountAddress) -> Option<AccountBalance>
Returns the balance of an account if it exists.
sourcepub fn account_balance_available(
&self,
address: AccountAddress
) -> Option<Amount>
pub fn account_balance_available( &self, address: AccountAddress ) -> Option<Amount>
Returns the available balance of an account if it exists.
sourcepub fn contract_balance(&self, address: ContractAddress) -> Option<Amount>
pub fn contract_balance(&self, address: ContractAddress) -> Option<Amount>
Returns the balance of an contract if it exists.
sourcepub fn contract_state_lookup(
&self,
address: ContractAddress,
key: &[u8]
) -> Option<Vec<u8>>
pub fn contract_state_lookup( &self, address: ContractAddress, key: &[u8] ) -> Option<Vec<u8>>
Helper method for looking up part of the state of a smart contract, which is a key-value store.
sourcepub fn account(
&self,
address: AccountAddress
) -> Result<&Account, AccountDoesNotExist>
pub fn account( &self, address: AccountAddress ) -> Result<&Account, AccountDoesNotExist>
Returns an immutable reference to an Account
.
sourcepub fn account_exists(&self, address: AccountAddress) -> bool
pub fn account_exists(&self, address: AccountAddress) -> bool
Check whether an Account
exists.
sourcepub fn contract_exists(&self, address: ContractAddress) -> bool
pub fn contract_exists(&self, address: ContractAddress) -> bool
Check whether a Contract
exists.
sourcepub fn set_exchange_rates(
&mut self,
micro_ccd_per_euro: ExchangeRate,
euro_per_energy: ExchangeRate
) -> Result<(), ExchangeRateError>
pub fn set_exchange_rates( &mut self, micro_ccd_per_euro: ExchangeRate, euro_per_energy: ExchangeRate ) -> Result<(), ExchangeRateError>
Try to set the exchange rates on the chain.
Will fail if they result in the cost of one energy being larger than
u64::MAX / 100_000_000_000
.
sourcepub fn tick_block_time(
&mut self,
duration: Duration
) -> Result<(), BlockTimeOverflow>
pub fn tick_block_time( &mut self, duration: Duration ) -> Result<(), BlockTimeOverflow>
Tick the block time on the Chain
by a Duration
.
Returns an error if ticking causes the block time to overflow.
§Example
// Block time defaults to 0.
let mut chain = Chain::new();
// Increase block time by 123 milliseconds.
chain.tick_block_time(Duration::from_millis(123)).unwrap();
// Block time has now increased.
assert_eq!(chain.block_time(), Timestamp::from_timestamp_millis(123));
sourcepub fn micro_ccd_per_euro(&self) -> ExchangeRate
pub fn micro_ccd_per_euro(&self) -> ExchangeRate
Return the current microCCD per euro exchange rate.
sourcepub fn euro_per_energy(&self) -> ExchangeRate
pub fn euro_per_energy(&self) -> ExchangeRate
Return the current euro per energy exchange rate.
sourcepub fn block_time(&self) -> Timestamp
pub fn block_time(&self) -> Timestamp
Return the current block time.
sourcepub fn external_query_block(
&self
) -> Result<BlockHash, ExternalNodeNotConfigured>
pub fn external_query_block( &self ) -> Result<BlockHash, ExternalNodeNotConfigured>
Return the block used for external queries by default.
The block can be set with ChainBuilder::external_query_block
when
building the Chain
.
This method returns an error if the external node has not been configured.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for Chain
impl !RefUnwindSafe for Chain
impl Send for Chain
impl Sync for Chain
impl Unpin for Chain
impl !UnwindSafe for Chain
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> FmtForward for T
impl<T> FmtForward for T
source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a tonic::Request
source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moresource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moresource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R ) -> R
source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.source§impl<T> Pointable for T
impl<T> Pointable for T
source§impl<T> Tap for T
impl<T> Tap for T
source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read moresource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read moresource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read moresource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read moresource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read moresource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read moresource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.