1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#![feature(non_exhaustive)]

use oasis_types::{AccountMeta, Address, Event};

pub trait Blockchain {
    /// Returns the name of this blockchain.
    fn name(&self) -> &str;

    /// Returns the block at a given height.
    fn block(&self, height: usize) -> Option<&dyn Block>;

    /// Returns a reference to the block at the current maximum height.
    fn last_block(&self) -> &dyn Block;

    /// Returns a mutable reference to the block at the current maximum height.
    fn last_block_mut(&mut self) -> &mut dyn Block;
}

pub trait Block {
    /// Returns the height of this block.
    fn height(&self) -> u64;

    /// Executes a RPC to `callee` with provided `input` and `gas` computational resources.
    /// `value` tokens will be transferred from the `caller` to the `callee`.
    /// The `caller` is charged `gas * gas_price` for the computation.
    /// A transaction that aborts (panics) will have its changes rolled back.
    /// This `transact` should be called by an Externally Owned Account (EOA).
    #[allow(clippy::too_many_arguments)]
    fn transact(
        &mut self,
        caller: Address,
        callee: Address,
        payer: Address,
        value: u128,
        input: &[u8],
        gas: u64,
        gas_price: u64,
    ) -> Box<dyn Receipt>;

    /// Returns the bytecode stored at `addr` or `None` if the account does not exist.
    fn code_at(&self, addr: &Address) -> Option<&[u8]>;

    /// Returns the metadata of the account stored at `addr`, or
    /// `None` if the account does not exist.
    fn account_meta_at(&self, addr: &Address) -> Option<AccountMeta>;

    /// Returns the state of the acount at `addr`, if it exists.
    fn state_at(&self, addr: &Address) -> Option<&dyn KVStore>;

    /// Returns the events emitted during the course of this block.
    fn events(&self) -> Vec<&Event>;

    /// Returns the receipts of transactions executed in this block.
    fn receipts(&self) -> Vec<&dyn Receipt>;
}

/// Represents the data and functionality available to a smart contract execution.
pub trait PendingTransaction {
    /// Returns the address of the current contract instance.
    fn address(&self) -> &Address;

    /// Returns the address of the sender of the transaction.
    fn sender(&self) -> &Address;

    /// Returns the value sent to the current transaction.
    fn value(&self) -> u128;

    /// Returns the input provided by the calling context.
    fn input(&self) -> &[u8];

    /// Executes a balance-transferring RPC to `callee` with provided input and value.
    /// The new transaction will inherit the gas parameters and gas payer of the top level
    /// transaction. The current account will be set as the sender.
    fn transact(&mut self, callee: Address, value: u128, input: &[u8]) -> Box<dyn Receipt>;

    /// Returns data to the calling transaction.
    fn ret(&mut self, data: &[u8]);

    /// Returns error data to the calling context.
    fn err(&mut self, data: &[u8]);

    /// Publishes a broascast message in this block.
    fn emit(&mut self, topics: &[&[u8]], data: &[u8]);

    /// Returns the state of the current account.
    fn state(&self) -> &dyn KVStore;

    /// Returns the mutable state of the current account.
    fn state_mut(&mut self) -> &mut dyn KVStoreMut;

    /// Returns the bytecode stored at `addr` or `None` if the account does not exist.
    fn code_at(&self, addr: &Address) -> Option<&[u8]>;

    /// Returns the metadata of the account stored at `addr`, or
    /// `None` if the account does not exist.
    fn account_meta_at(&self, addr: &Address) -> Option<AccountMeta>;
}

/// Interface for a Blockchain-flavored key-value store.
pub trait KVStore {
    /// Returns whether the key is present in account storage.
    fn contains(&self, key: &[u8]) -> bool;

    /// Returns the data stored in the account at `addr` under the given `key`.
    fn get(&self, key: &[u8]) -> Option<Vec<u8>>;
}

pub trait KVStoreMut: KVStore {
    /// Sets the data stored in the account under the given  `key`.
    /// Overwrites any existing data.
    fn set(&mut self, key: &[u8], value: &[u8]);

    /// Removes the data stored in the account under the given  `key`.
    fn remove(&mut self, key: &[u8]);
}

pub trait Receipt {
    fn caller(&self) -> &Address;

    fn callee(&self) -> &Address;

    /// Returns the total gas used during the execution of the transaction.
    fn gas_used(&self) -> u64;

    /// Returns the events emitted during the transaction.
    fn events(&self) -> Vec<&Event>;

    /// Returns the outcome of this transaction.
    fn outcome(&self) -> TransactionOutcome;

    /// Returns the output of the transaction.
    fn output(&self) -> &[u8];

    /// Returns whether the transaction that produced this receipt was reverted.
    fn reverted(&self) -> bool {
        match self.outcome() {
            TransactionOutcome::Success => false,
            _ => true,
        }
    }
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[non_exhaustive]
#[repr(u16)]
pub enum TransactionOutcome {
    Success,
    InsufficientFunds,
    InsufficientGas,
    InvalidInput,
    InvalidCallee,
    Aborted, // recoverable error
    Fatal,
}

impl TransactionOutcome {
    pub fn reverted(self) -> bool {
        match self {
            TransactionOutcome::Success => false,
            _ => true,
        }
    }
}