initial commit phase .

This commit is contained in:
|| Prof. - Xadk3! 2023-04-17 07:11:06 +00:00
parent 50e2f6d92d
commit a5f1d08a5e
6 changed files with 4517 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
/target
*db*
__pycache__/
.o
.so
.exe
.pyc
.ts
*_no.git_*
venv/
*venv*

3902
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "evmSH"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.70"
ethers = "2.0.3"
revm = "3.1.1"
tokio = "1.27.0"

471
bpnpcode.js Executable file
View File

@ -0,0 +1,471 @@
#!/usr/bin/env node
/* note: it can crash a net while running on kernel-space */
/*jshint es5:false, asi:true, quotmark:false, eqeqeq:false, forin: false */
/*
* (c) 2011-14 Tim Becker, see file LICENSE for details
*/
/*
* Provides functionality for bencoding and decoding as use in
* bittorrent and described in: http://www.bittorrent.org/beps/bep_0003.html
*
* Encoding is as follows:
*
* var benc = require('bncode'),
* exmp = {}
*
* exmp.bla = "blup"
* exmp.foo = "bar"
* exmp.one = 1
* exmp.woah = {}
* exmp.woah.arr = []
* exmp.woah.arr.push(1)
* exmp.woah.arr.push(2)
* exmp.woah.arr.push(3)
* exmp.str = new Buffer("Buffers work too")
*
* var bencBuffer = benc.encode(exmp) i
*
* // d3:bla4:blup3:foo3:bar3:onei1e4:woahd3:arr \
* // li1ei2ei3eee3:str16:Buffers work tooe
*
*
* Decoding will work in progressively, e.g. if you're receiving partial
* bencoded strings on the network:
*
* var benc = require("bncode"),
* buf = null
*
* decoder = new bncode.decoder()
* while (buf = receiveData()) {
* decoder.decode(buf)
* }
*
* log(decoder.result())
*
*
* Or "all in one"
*
* var benc = require("bncode"),
* buf = getBuffer(),
* dec = benc.decode(buf)
*
* log(dec.bla)
*
*
* There are some subtleties concerning bencoded strings. These are
* decoded as Buffer objects because they are just strings of raw bytes
* and as such would wreak havoc with multi byte strings in javascript.
*
* The exception to this is strings that appear as keys in bencoded
* dicts. These are decoded as Javascript Strings, as they should always
* be strings of (ascii) characters and if they weren't decoded as JS
* Strings, dict's would map to Javascript objects with properties.
*
*/
exports.encode = Bencode
exports.decoder = Bdecode
exports.decode = decode
exports.Stream = Stream
var inherits = require('util').inherits
var Transform = require('stream').Transform
var I = 'i'.charCodeAt(0)
var L = 'l'.charCodeAt(0)
var E = 'e'.charCodeAt(0)
var D = 'd'.charCodeAt(0)
var COLON = ':'.charCodeAt(0)
var DASH = '-'.charCodeAt(0)
var STATE_INITIAL = 0
var STATE_STATE_STRING_LEN = STATE_INITIAL + 1
var STATE_STRING = STATE_STATE_STRING_LEN + 1
var STATE_COLON = STATE_STRING + 1
var STATE_STATE_INTEGER = STATE_COLON + 1
var STATE_INTEGER = STATE_STATE_INTEGER + 1
/*
* This is the internal state machine for taking apart bencoded strings,
* it's not exposed in the eports. It's constructed with four callbacks
* that get fired when:
*
* cb: a value (string or number) is encountered
* cb_list: a begin list element is encountered
* cb_dict: a beginning of dictionary is encountered.
* cd_end: an end element, wheter dict or list is encountered
*
* Once constructed, the machine may be fed with buffers containing
* partial bencoded string. Call `consistent` to check whether the
* current state is consistent, e.g. not smack-dap in the middle of
* a string or a number and if the dict, list and end calls balance
*
*
* The functionality being so rudimentary requires some more state and
* logic in the code executing the machine, for this see Context, below.
*
*/
function BdecodeSMachine (cb, cb_list, cb_dict, cb_end) {
var depth = 0
var state = STATE_INITIAL
this.consistent = function () {
return state === STATE_INITIAL && depth === 0
}
var strLen = 0
var str = ''
var _int = 0
var neg = false
this.parse = function (buffer, encoding) {
if (typeof buffer === 'string') {
buffer = new Buffer(buffer, encoding || 'utf8')
}
for (var pos = 0; pos !== buffer.length; ++pos) {
switch (state) {
case STATE_INITIAL:
switch (buffer[pos]) {
case 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x34:
case 0x35:
case 0x36:
case 0x37:
case 0x38:
case 0x39:
state = STATE_STATE_STRING_LEN
strLen = 0
strLen += buffer[pos] - 0x30
break
case I:
state = STATE_STATE_INTEGER
_int = 0
neg = false
break
case L:
state = STATE_INITIAL
depth += 1
cb_list()
break
case D:
state = STATE_INITIAL
depth += 1
cb_dict()
break
case E:
state = STATE_INITIAL
depth -= 1
if (depth < 0) {
throw new Error('end with no beginning: ' + pos)
} else {
cb_end()
}
break
}
break
case STATE_STATE_STRING_LEN:
if (integer(buffer[pos])) {
strLen *= 10
strLen += buffer[pos] - 0x30
} else {
str = new Buffer(strLen)
pos -=1
state = STATE_COLON
}
break
case STATE_COLON:
if (buffer[pos] !== COLON) {
throw new Error('not a colon at: ' + pos.toString(16))
}
state = STATE_STRING
// in case this is a zero length string, there's
// no bytes to be collected.
if (0 === strLen) {
cb(new Buffer(0))
state = STATE_INITIAL
}
break
case STATE_STRING:
if (0 === strLen) {
cb(str)
state = STATE_INITIAL
} else {
//str += String.fromCharCode(buffer[pos]) // not unicode safe..
str[str.length-strLen] = buffer[pos]
strLen -= 1
if (0 === strLen) {
cb(str)
state = STATE_INITIAL
}
}
break
case STATE_STATE_INTEGER:
state = STATE_INTEGER
if (buffer[pos] === DASH) {
neg = true // handle neg and zero within value.
break
} // else fall through
case STATE_INTEGER:
if (integer(buffer[pos])) {
_int *= 10
_int += buffer[pos] - 0x30
} else if (buffer[pos] === E) {
var ret = neg ? 0 - _int : _int
cb(ret)
state = STATE_INITIAL
} else {
throw new Error('not part of int at:'+pos.toString(16))
}
break
} // switch state
} // for buffer
} // function parse
function integer (value) {
// check that value is a number and that
// its value is ascii integer.
if (typeof value !== 'number') {
return false
}
return between(value, 0x30, 0x39)
}
function between (val, min, max) {
return (min <= val && val <= max)
}
} // end BdecodeSMachine
/*
* The exported decode functionality.
*/
function Bdecode () {
// markers
var DICTIONARY_START = {}
var LIST_START = {}
var Context = function () {
var self = this
var stack = []
this.cb = function (o) {
stack.push(o)
}
this.cb_list = function () {
self.cb(LIST_START)
}
this.cb_dict = function () {
self.cb(DICTIONARY_START)
}
this.cb_end = function () {
// unwind the stack until either a DICTIONARY_START or LIST_START is
// found, create arr or hash, stick unwound stack on, push arr or hash
// back onto stack
var obj = null
var tmp_stack = []
while ((obj = stack.pop()) !== undefined) {
if (LIST_START === obj) {
var obj2 = null
var list = []
while((obj2 = tmp_stack.pop()) !== undefined) {
list.push(obj2)
}
self.cb(list)
break
} else if (DICTIONARY_START === obj) {
var key = null
var val = null
var dic = {}
while ((key = tmp_stack.pop()) !== undefined && (val = tmp_stack.pop()) !== undefined) {
dic[key.toString()] = val
}
if (key !== undefined && dic[key] === undefined) {
throw new Error('uneven number of keys and values A')
}
self.cb(dic)
break
} else {
tmp_stack.push(obj)
}
}
if (tmp_stack.length > 0) {
// could this case even occur?
throw new Error('uneven number of keys and values B')
}
}
this.result = function () {
return stack
}
}
var self = this
var ctx = new Context()
var smachine = new BdecodeSMachine(ctx.cb, ctx.cb_list, ctx.cb_dict, ctx.cb_end)
this.result = function () {
if (!smachine.consistent()) {
throw new Error('not in consistent state. More bytes coming?')
}
return ctx.result()
}
this.decode = function (buf, encoding) {
smachine.parse(buf, encoding)
}
}
function Bencode (obj) {
var self = this
var to_encode = obj
var buffer = null
switch (typeof obj) {
case 'string':
return encodeString(obj)
case 'number':
return encodeNumber(obj)
case 'object':
if (obj instanceof Array) {
return encodeList(obj)
} else if (Buffer.isBuffer(obj)) {
return encodeBuffer(obj)
} else {
// assume it's a hash
return encodeDict(obj)
}
}
function encodeString (obj) {
var blen = Buffer.byteLength(obj)
var len = blen.toString(10)
var buf = new Buffer(len.length + 1 + blen)
buf.write(len, 0, 'ascii')
buf.write(':', len.length, 'ascii')
buf.write(obj, len.length + 1, 'utf8')
return buf
}
function encodeNumber (num) {
var n = num.toString(10)
var buf = new Buffer(n.length + 2)
buf.write('i', 0)
buf.write(n, 1)
buf.write('e', n.length + 1)
return buf
}
function encodeDict (obj) {
var func = function (obj, pos) {
var keys = Object.keys(obj).sort()
keys.forEach(function (key) {
var val = new Bencode(obj[key])
key = new Bencode(key)
ensure(key.length + val.length, pos)
key.copy(buffer, pos, 0)
pos += key.length
val.copy(buffer, pos, 0)
pos += val.length
})
return pos
}
return assemble(obj, 'd', func)
}
function encodeList (obj) {
var func = function(obj, pos) {
obj.forEach(function (o) {
var elem = new Bencode(o)
ensure(elem.length, pos)
elem.copy(buffer, pos, 0)
pos += elem.length
})
return pos
}
return assemble(obj, 'l', func)
}
function encodeBuffer (obj) {
var len = obj.length.toString(10)
var buf = new Buffer(len.length + 1 + obj.length)
buf.write(len, 0, 'ascii')
buf.write(':', len.length, 'ascii')
obj.copy(buf, len.length + 1, 0)
return buf
}
function assemble (obj, prefix, func) {
var pos = 0
ensure(1024, 0)
buffer.write(prefix, pos++)
pos = func(obj, pos)
ensure(1, pos)
buffer.write('e', pos++)
return buffer.slice(0, pos)
}
function ensure (num, pos) {
if (!buffer) {
buffer = new Buffer(num)
} else {
if (buffer.length > num + pos + 1) {
return
} else {
var buf2 = new Buffer(buffer.length + num)
buffer.copy(buf2, 0, 0)
buffer = buf2
}
}
}
}
function decode (buffer, encoding) {
var decoder = new Bdecode()
decoder.decode(buffer, encoding)
return decoder.result()[0]
}
function Stream (options) {
options = options || {}
options.objectMode = true
Transform.call(this, options)
this._decoder = new Bdecode()
}
inherits(Stream, Transform)
Stream.prototype._transform = function (chunk, encoding, callback) {
try {
this._decoder.decode(chunk, encoding)
callback(null)
} catch(err) {
callback(err)
}
}
Stream.prototype._flush = function (callback) {
this.push(this._decoder.result()[0])
callback(null)
}

9
src/main.rs Normal file
View File

@ -0,0 +1,9 @@
use waddaFork::tait;
#[tokio::main]
async fn main() -> Result<()> {
// create ethers client and wrap it in Arc<M>
// let client = Arc::new(nick.local.CLIENT);
await tait().?;
println!("Hello, world!");
}

112
src/waddaFork.rs Normal file
View File

@ -0,0 +1,112 @@
use std::{str::FromStr, sync::Arc};
use anyhow::{Ok, Result};
use bytes::Bytes;
use ethers::{
abi::parse_abi,
prelude::BaseContract,
providers::{Http, Provider},
};
use revm::{
db::{CacheDB, EmptyDB, EthersDB},
primitives::{ExecutionResult, Output, TransactTo, B160, U256 as rU256},
Database, EVM,
};
#[tokio::main]
async fn tait() -> Result<()> {
// create ethers client and wrap it in Arc<M>
let client = Provider::<Http>::try_from(
"https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27",
)?;
let client = Arc::new(client);
// ----------------------------------------------------------- //
// Storage slots of UniV2Pair contract //
// =========================================================== //
// storage[5] = factory: address //
// storage[6] = token0: address //
// storage[7] = token1: address //
// storage[8] = (res0, res1, ts): (uint112, uint112, uint32) //
// storage[9] = price0CumulativeLast: uint256 //
// storage[10] = price1CumulativeLast: uint256 //
// storage[11] = kLast: uint256 //
// =========================================================== //
// choose slot of storage that you would like to transact with
let slot = rU256::from(8);
// ETH/USDT pair on Uniswap V2
let pool_address = B160::from_str("0x252ea274ff957494274057ed94844ffd7184e21f")?;
// generate abi for the calldata from the human readable interface
let abi = BaseContract::from(
parse_abi(&[
"function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)",
])?
);
// encode abi into Bytes
let encoded = abi.encode("getReserves", ())?;
// initialize new EthersDB
let mut ethersdb = EthersDB::new(Arc::clone(&client), None).unwrap();
// query basic properties of an account incl bytecode
let acc_info = ethersdb.basic(pool_address).unwrap().unwrap();
// query value of storage slot at account address
let value = ethersdb.storage(pool_address, slot).unwrap();
// initialise empty in-memory-db
let mut cache_db = CacheDB::new(EmptyDB::default());
// insert basic account info which was generated via Web3DB with the corresponding address
cache_db.insert_account_info(pool_address, acc_info);
// insert our pre-loaded storage slot to the corresponding contract key (address) in the DB
cache_db
.insert_account_storage(pool_address, slot, value)
.unwrap();
// initialise an empty (default) EVM
let mut evm = EVM::new();
// insert pre-built database from above
evm.database(cache_db);
// fill in missing bits of env struc
// change that to whatever caller you want to be
evm.env.tx.caller = B160::from_str("0x0000000000000000000000000000000000000000")?;
// account you want to transact with
evm.env.tx.transact_to = TransactTo::Call(pool_address);
// calldata formed via abigen
evm.env.tx.data = Bytes::from(hex::decode(hex::encode(&encoded))?);
// transaction value in wei
evm.env.tx.value = rU256::try_from(0)?;
// execute transaction without writing to the DB
let ref_tx = evm.transact_ref().unwrap();
// select ExecutionResult struct
let result = ref_tx.result;
// unpack output call enum into raw bytes
let value = match result {
ExecutionResult::Success { output, .. } => match output {
Output::Call(value) => Some(value),
_ => None,
},
_ => None,
};
// decode bytes to reserves + ts via ethers-rs's abi decode
let (reserve0, reserve1, ts): (u128, u128, u32) =
abi.decode_output("getReserves", value.unwrap())?;
// Print emulated getReserves() call output
println!("Reserve0: {:#?}", reserve0);
println!("Reserve1: {:#?}", reserve1);
println!("Timestamp: {:#?}", ts);
Ok(())
}