Casper
The Casper backend allows you to compile your contracts into WASM files which can be deployed onto Casper Blockchain and lets you to easily run them against Casper's Execution Engine locally.
Types
A struct to be written into the storage must implement OdraType
which is defined as follow:
pub trait OdraType:
casper_types::CLTyped +
casper_types::bytesrepr::ToBytes +
casper_types::bytesrepr::FromBytes {}
The other exposed types are:
CallArgs
- wraps around casper'sRuntimeArgs
;Balance
- U512 type alias;BlockTime
- u64 type alias;Address
- an enum that encapsulates casper'sAccountHash
andContractPackageHash
Contract Env
As with any other backend, Casper Backend must implement the same features, but some do not have native support. Let's take a closer look at how Odra overcomes these hindrances.
Events
An event is not a first-class citizen in Casper like in Ethereum, so Odra mimics it. As you've already learned from the events article, in Odra you emit an event, similarly, you would do it in Solidity.
Under the hood, Odra creates two URef
s in the global state:
__events
- a dictionary that stores events' data.__events_length
- the evens count.
So, Events
are nothing different from any other data stored by a contract.
A struct to be an event must implement SerializableEvent
which is defined as follow:
pub trait SerializableEvent:
odra_types::event::OdraEvent +
casper_types::CLTyped +
casper_types::bytesrepr::ToBytes +
casper_types::bytesrepr::FromBytes {}
Payable
The first Odra idiom is a Contract Main Purse
. It is a purse associated with a contract. The purse is created lazily - when the first transfer to the contract occurs, a proper URef
and a purse are created and stored under the __contract_main_purse
key.
Casper does not allow direct transfers from an account to a contract, so Odra comes up with the second idiom - a Cargo Purse
. It is a one-time-use purse proxy between an account and a contract. First, motes go from the account to the cargo purse and then to the contract's main purse.
Behind the scenes, Odra handles an account-contract transfer via a cargo purse when a function is marked as payable. If under the way something goes wrong with the transfer, the contract reverts.
The transferred amount can be read inside the contract by calling contract_env::attached_value()
.
Odra expects the cargo_purse
runtime argument to be attached to a contract call.
Revert
In Casper, we can stop the execution pretty straightforwardly - call the runtime::revert()
.
Odra adds an extra abstraction layer - in a contract ExecutionError
s are defined, which ultimately are transformed into Casper's ApiError::User
.
Context
Casper equips developers with very low-level tooling, which can be cumbersome for newcomers. If you want to check who called the contract or its address, you can not do it off-hand - you must analyze the call stack.
The contract_env::self_address()
function takes the first element of the callstack (runtime::get_call_stack()
) and casts it to Address
.
The contract_env::caller()
function takes the second element of the call stack (runtime::get_call_stack()
) and casts it to Address
.
As mentioned in the [Payable] section, to store CSPR, each contract creates its purse. To read the contract balance, you call contract_env::self_balance
, which checks the balance of the purse stored under __contract_main_purse
.
Test Env
Test environment allows you to test wasm contracts before you deploy them onto the testnet or livenet. It is built on top of the Casper Execution Engine
.
In your test, you can freely switch execution context by setting as a caller (test_env::set_caller()
) one of the 20 predefined accounts. Each account possesses the default amount of Motes
(100_000_000_000_000_000).
The Test Env internally keeps track of the current block time
, error
and attached value
.
Each test is executed on a fresh instance of the Test Env.
Usage
Name of the Casper backend in Odra is casper
, so to run the tests against it, simply pass it as a -b
parameter:
cargo odra test -b casper
If you want to just generate a wasm file, simply run:
cargo odra build -b casper
Execution
First thing Odra does with your code, is similar to the one used in MockVM -
a list of entrypoints is generated, thanks to the #[odra::module]
macro.