Skip to content

Instantly share code, notes, and snippets.

@eira-fransham
Last active April 25, 2018 14:48
Show Gist options
  • Save eira-fransham/faf457970517500a403f8fb81a50440c to your computer and use it in GitHub Desktop.
Save eira-fransham/faf457970517500a403f8fb81a50440c to your computer and use it in GitHub Desktop.
// Low-level interface, we can implement a higher-level interface as a library
mod pwasm {
use std::marker::PhantomData;
pub struct ContractDef<State> {
state: State,
iterate: for<'a> fn(&'a EthEnv, State, MessageData) -> (State, ReturnData),
}
// Will it ever be possible to get arbitrary blocks?
pub struct Block(());
impl Block {
pub fn beneficiary() -> U256 {
unimplemented!();
}
pub fn timestamp() -> U256 {
unimplemented!();
}
pub fn number() -> U256 {
unimplemented!();
}
pub fn difficulty() -> U256 {
unimplemented!();
}
pub fn gas_limit() -> U256 {
unimplemented!();
}
}
pub struct EthEnv(());
impl EthEnv {
fn blockchain(&self) -> &BlockChain {
unimplemented!()
}
// We use different types for remote vs local contracts since
// they require different functions to get the code
// `impl Contract` is a `RemoteContract`
fn contract_at(&self) -> Result<&impl Contract> {
unimplemented!()
}
// `impl Contract` is a `LocalContract`
fn current_contract(&self) -> Result<&impl Contract> {
unimplemented!()
}
}
pub struct BlockChain(());
pub impl BlockChain {
pub fn current(&self) -> &Block {
unimplemented!();
}
pub fn block_hash(&self, number: u8) -> U256 {
unimplemented!();
}
}
pub trait Contract {
// Compiles to `CODESIZE` + `CODECOPY` (TODO: This should be dynamically-sized but
// owned but we can't do that without `alloca`, so we can just write a `Box<[u8]>`-
// esque type that allocates on the "heap")
fn code(&self) -> &[u8];
fn call(&self, method: &[u8], args: &[u8]) -> &[u8];
}
}
#[derive(Serialize, Deserialize)]
struct Sender(pwasm::Sender);
fn make_contract(deploy_data: DeployData) -> ContractDef<Sender> {
ContractBuilder::with_data(Sender(deploy_data.sender()))
.call(|sender| {
let owner = sender.0;
Ok(owner.as_ref())
})
.build()
}
#[derive(Serialize, Deserialize)]
struct State {
supply: U256,
}
fn make_contract(deploy_data: DeployData) -> ContractDef<State> {
let another_contract: MyType = MyType::at(some_address);
ContractBuilder::with_data(State { supply: SUPPLY, ctrct: another_contract })
// Takes a type parameter which is the argument type for
// this message. Must implement `Deserialize`.
.on_msg::<()>("totalSupply", |this, ()| {
ANOTHER_CONTRACT.call("my_msg", MyData);
state.supply
})
}
// The wasm interpreter runs this function and gets the returned `iterate` function, then
// "compiles" the deployed contract by removing all code that is not referenced by it.
fn deploy(deploy_data: DeployData) -> ContractDef<MyState> {
#[derive(Serialize, Deserialize)]
struct MyState;
ContractDef {
state: MyState,
iterate: |environment: &EthEnv, state: MyState, _msg: MessageData| state,
}
}
// This takes the `deploy` function and converts the generic `ContractDef` to a monomorphic
// type (probably ContractDef<&[u8]>), then exports a `#[no_mangle]` function called
// `__ethereum_deploy` or suchlike.
eth_deploy!(deploy);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment