4 releases

0.11.0 May 7, 2019
0.11.0-beta.3 Apr 29, 2019
0.11.0-beta.2 Apr 28, 2019
0.11.0-beta.0 Apr 24, 2019

#17 in #pre-compiled

Apache-2.0 and maybe GPL-3.0

28KB
308 lines

Network-Agnostic SputnikVM Patches

This crate provides re-exports of the DynamicPatch API, and a set of precompiled contracts covering everything up to ETH Constantinople

There are two major approaches to the EVM configuration:

Examples for both approaches may be found below

Dynamic Patch API

DynamicPatch API is most useful for multi-network clients like multi-geth, where it's preferable to configure the EVM feature-wise, instead of fork-wise.

Example

use evm::{SeqTransactionVM, ValidTransaction, TransactionAction, HeaderParams};
use evm_network::{DynamicPatch, DynamicAccountPatch, PRECOMPILEDS};
use bigint::{Gas, U256, Address};
use std::rc::Rc;

fn main() {
  let transaction = ValidTransaction {
     caller: Some(Address::default()),
     gas_price: Gas::zero(),
     gas_limit: Gas::max_value(),
     action: TransactionAction::Create,
     value: U256::zero(),
     input: Rc::new(Vec::new()),
     nonce: U256::zero()
  };

  // Block Header
  let header = HeaderParams {
     beneficiary: Address::default(),
     timestamp: 0,
     number: U256::zero(),
     difficulty: U256::zero(),
     gas_limit: Gas::zero()
  };

  // Account Patch for ETC MainNet
  let account_patch = DynamicAccountPatch {
     initial_nonce: U256::zero(),
     initial_create_nonce: U256::zero(),
     empty_considered_exists: true,
     allow_partial_change: true
  };

  // Patch for Constantinople hardfork
  let patch = DynamicPatch {
     account_patch,
     code_deposit_limit: None,
     callstack_limit: 1024,
     gas_extcode: Gas::from(700_usize),
     gas_balance: Gas::from(400_usize),
     gas_sload: Gas::from(200_usize),
     gas_suicide: Gas::from(5000_usize),
     gas_suicide_new_account: Gas::from(25000_usize),
     gas_call: Gas::from(700_usize),
     gas_expbyte: Gas::from(50_usize),
     gas_transaction_create: Gas::from(32000_usize),
     force_code_deposit: false,
     has_delegate_call: true,
     has_static_call: true,
     has_revert: true,
     has_return_data: true,
     has_bitwise_shift: true,
     has_extcodehash: true,
     has_create2: true,
     has_reduced_sstore_gas_metering: true,
     err_on_call_with_more_gas: false,
     call_create_l64_after_gas: true,
     memory_limit: usize::max_value(),
     // Enable all eight precompiled contracts by their addresses
     enabled_precompileds: (0x1..=0x8).into_iter().map(Address::from).collect(),
     precompileds: &PRECOMPILEDS
  };

  SeqTransactionVM::new(
      &patch,
      transaction,
      header
  );
}

Patch API

If you need just a single network or even a single feature-set, use the Patch trait directly, that allows to create custom feature sets without DynamicPatch's tiny overhead.

Example

use evm::{SeqTransactionVM, ValidTransaction, TransactionAction, HeaderParams, Precompiled};
use evm_network::{AccountPatch, Patch, PRECOMPILEDS};
use bigint::{Gas, U256, Address};
use std::rc::Rc;

struct MainnetAccountPatch;
impl AccountPatch for MainnetAccountPatch {
   fn initial_nonce(&self) -> U256 { U256::zero() }
   fn initial_create_nonce(&self) -> U256 { U256::zero() }
   fn empty_considered_exists(&self) -> bool { true }
}

static MAINNET_ACCOUNT_PATCH: MainnetAccountPatch = MainnetAccountPatch;

struct ConstantinoplePatch;
impl Patch for ConstantinoplePatch {
   type Account = MainnetAccountPatch;
   fn account_patch(&self) -> &'static Self::Account { &MAINNET_ACCOUNT_PATCH }
   fn code_deposit_limit(&self) -> Option<usize> { None }
   fn callstack_limit(&self) -> usize { 1024 }
   fn gas_extcode(&self) -> Gas { Gas::from(700usize) }
   fn gas_balance(&self) -> Gas { Gas::from(400usize) }
   fn gas_sload(&self) -> Gas { Gas::from(200usize) }
   fn gas_suicide(&self) -> Gas { Gas::from(5000usize) }
   fn gas_suicide_new_account(&self) -> Gas { Gas::from(25000usize) }
   fn gas_call(&self) -> Gas { Gas::from(700usize) }
   fn gas_expbyte(&self) -> Gas { Gas::from(50usize) }
   fn gas_transaction_create(&self) -> Gas { Gas::from(32000usize) }
   fn force_code_deposit(&self) -> bool { false }
   fn has_delegate_call(&self) -> bool { true }
   fn has_static_call(&self) -> bool { true }
   fn has_revert(&self) -> bool { true }
   fn has_return_data(&self) -> bool { true }
   fn has_bitwise_shift(&self) -> bool { true }
   fn has_create2(&self) -> bool { true }
   fn has_extcodehash(&self) -> bool { true }
   fn has_reduced_sstore_gas_metering(&self) -> bool { true }
   fn err_on_call_with_more_gas(&self) -> bool { false }
   fn call_create_l64_after_gas(&self) -> bool { true }
   fn memory_limit(&self) -> usize { usize::max_value() }
   fn is_precompiled_contract_enabled(&self, address: &Address) -> bool {
       match address.low_u64() {
           0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 => true,
           _ => false,
       }
   }
   fn precompileds(&self) -> &'static [(Address, Option<&'static [u8]>, &'static Precompiled)] {
       &PRECOMPILEDS
   }
}


fn main() {
  let transaction = ValidTransaction {
     caller: Some(Address::default()),
     gas_price: Gas::zero(),
     gas_limit: Gas::max_value(),
     action: TransactionAction::Create,
     value: U256::zero(),
     input: Rc::new(Vec::new()),
     nonce: U256::zero()
  };

  // Block Header
  let header = HeaderParams {
     beneficiary: Address::default(),
     timestamp: 0,
     number: U256::zero(),
     difficulty: U256::zero(),
     gas_limit: Gas::zero()
  };

  let patch = ConstantinoplePatch;

  SeqTransactionVM::new(
      &patch,
      transaction,
      header
  );
}

Dependencies

~6MB
~53K SLoC