mirror of
https://github.com/arnaucube/evm-rs.git
synced 2026-02-02 17:06:40 +01:00
Update SSTORE(0x55) to EIP 3529&1283
This commit is contained in:
@@ -10,6 +10,7 @@ pub struct Stack {
|
|||||||
pub calldata_i: usize,
|
pub calldata_i: usize,
|
||||||
pub calldata_size: usize,
|
pub calldata_size: usize,
|
||||||
pub stack: Vec<[u8; 32]>,
|
pub stack: Vec<[u8; 32]>,
|
||||||
|
pub storage_committed: HashMap<[u8; 32], Vec<u8>>,
|
||||||
pub storage: HashMap<[u8; 32], Vec<u8>>,
|
pub storage: HashMap<[u8; 32], Vec<u8>>,
|
||||||
pub mem: Vec<u8>,
|
pub mem: Vec<u8>,
|
||||||
pub gas: u64,
|
pub gas: u64,
|
||||||
@@ -23,6 +24,7 @@ impl Stack {
|
|||||||
calldata_i: 0,
|
calldata_i: 0,
|
||||||
calldata_size: 32,
|
calldata_size: 32,
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
|
storage_committed: HashMap::new(),
|
||||||
storage: HashMap::new(),
|
storage: HashMap::new(),
|
||||||
mem: Vec::new(),
|
mem: Vec::new(),
|
||||||
gas: 10000000000,
|
gas: 10000000000,
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ const GSTORAGEKILL: usize = 5000;
|
|||||||
const GSTORAGEMOD: usize = 5000;
|
const GSTORAGEMOD: usize = 5000;
|
||||||
const GSTORAGEADD: usize = 20000;
|
const GSTORAGEADD: usize = 20000;
|
||||||
|
|
||||||
|
const NETSSTORENOOPGAS: u64 = 200;
|
||||||
|
const NETSSTOREINITGAS: u64 = 20000;
|
||||||
|
const NETSSTORECLEARREFUND: u64 = 15000;
|
||||||
|
const NETSSTORERESETCLEARREFUND: u64 = 19800;
|
||||||
|
const NETSSTORERESETREFUND: u64 = 4800;
|
||||||
|
const NETSSTORECLEANGAS: u64 = 5000;
|
||||||
|
const NETSSTOREDIRTYGAS: u64 = 200;
|
||||||
|
|
||||||
const GEXPONENTBYTE: usize = 10; // cost of EXP exponent per byte
|
const GEXPONENTBYTE: usize = 10; // cost of EXP exponent per byte
|
||||||
const EXP_SUPPLEMENTAL_GAS: usize = 40;
|
const EXP_SUPPLEMENTAL_GAS: usize = 40;
|
||||||
const GCOPY: usize = 3; // cost to copy one 32 byte word
|
const GCOPY: usize = 3; // cost to copy one 32 byte word
|
||||||
@@ -40,7 +48,6 @@ pub struct Opcode {
|
|||||||
pub ins: u32,
|
pub ins: u32,
|
||||||
pub outs: u32,
|
pub outs: u32,
|
||||||
pub gas: u64,
|
pub gas: u64,
|
||||||
// operation: fn(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_opcode(name: &str, ins: u32, outs: u32, gas: u64) -> Opcode {
|
pub fn new_opcode(name: &str, ins: u32, outs: u32, gas: u64) -> Opcode {
|
||||||
@@ -378,28 +385,66 @@ impl Stack {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn sstore(&mut self) -> Result<(), String> {
|
pub fn sstore(&mut self) -> Result<(), String> {
|
||||||
// TODO WIP
|
// https://eips.ethereum.org/EIPS/eip-3529
|
||||||
|
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1283.md
|
||||||
|
// 1. If current value equals new value (this is a no-op), 200 gas is deducted.
|
||||||
|
// 2. If current value does not equal new value
|
||||||
|
// 2.1. If original value equals current value (this storage slot has not been changed by the current execution context)
|
||||||
|
// 2.1.1. If original value is 0, 20000 gas is deducted.
|
||||||
|
// 2.1.2. Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter.
|
||||||
|
// 2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses.
|
||||||
|
// 2.2.1. If original value is not 0
|
||||||
|
// 2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0.
|
||||||
|
// 2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter.
|
||||||
|
// 2.2.2. If original value equals new value (this storage slot is reset)
|
||||||
|
// 2.2.2.1. If original value is 0, add 19800 gas to refund counter.
|
||||||
|
// 2.2.2.2. Otherwise, add 4800 gas to refund counter.
|
||||||
|
|
||||||
|
let empty: Vec<u8> = Vec::new();
|
||||||
let key = self.pop()?;
|
let key = self.pop()?;
|
||||||
let value = self.pop()?;
|
let value = self.pop()?;
|
||||||
if self.storage.contains_key(&key) {
|
let original = match self.storage_committed.get(&key) {
|
||||||
let old_value = self.storage.get(&key).unwrap();
|
Some(v) => v.clone(),
|
||||||
if &value.to_vec() == old_value {
|
None => empty.clone(),
|
||||||
// if the new value is the same as the old one, do not set
|
};
|
||||||
|
let current = match self.storage.get(&key) {
|
||||||
|
Some(v) => v.clone(),
|
||||||
|
None => {
|
||||||
|
self.gas -= 2100;
|
||||||
|
empty.clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if current == value {
|
||||||
|
self.gas -= NETSSTORENOOPGAS;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if original == current {
|
||||||
|
if original.is_empty() {
|
||||||
|
self.gas -= NETSSTOREINITGAS;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// if value (from self.pop()) does not exist in the stack, is a STORAGEKILL TODO
|
if value.is_empty() {
|
||||||
println!("mingas {:?}", GSTORAGEMOD);
|
self.gas += NETSSTORECLEARREFUND;
|
||||||
self.gas -= GSTORAGEMOD as u64;
|
}
|
||||||
} else {
|
self.gas -= NETSSTORECLEANGAS;
|
||||||
// if value does not exist, substract gas for the addition
|
return Ok(());
|
||||||
println!("mingas {:?}", GSTORAGEADD);
|
|
||||||
self.gas -= GSTORAGEADD as u64;
|
|
||||||
}
|
}
|
||||||
println!(
|
if !original.is_empty() {
|
||||||
"insert {:?} - {:?}",
|
if current.is_empty() {
|
||||||
vec_u8_to_hex(key.to_vec()),
|
self.gas -= NETSSTORECLEARREFUND;
|
||||||
vec_u8_to_hex(value.to_vec())
|
} else if value.is_empty() {
|
||||||
);
|
self.gas += NETSSTORECLEARREFUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if original == value {
|
||||||
|
if original.is_empty() {
|
||||||
|
self.gas += NETSSTORERESETCLEARREFUND;
|
||||||
|
} else {
|
||||||
|
self.gas += NETSSTORERESETREFUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.gas -= NETSSTOREDIRTYGAS;
|
||||||
self.storage.insert(key, value.to_vec());
|
self.storage.insert(key, value.to_vec());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,10 +216,10 @@ fn execute_opcodes_9() {
|
|||||||
s.execute(&code, &calldata, false).unwrap();
|
s.execute(&code, &calldata, false).unwrap();
|
||||||
|
|
||||||
// assert_eq!(s.gas, 9999977788); // TODO WIP geth reported gas
|
// assert_eq!(s.gas, 9999977788); // TODO WIP geth reported gas
|
||||||
assert_eq!(s.gas, 9999974988);
|
assert_eq!(s.gas, 9999955788);
|
||||||
assert_eq!(s.pc, 10);
|
assert_eq!(s.pc, 10);
|
||||||
assert_eq!(s.stack.len(), 0);
|
assert_eq!(s.stack.len(), 0);
|
||||||
assert_eq!(s.storage.len(), 1);
|
assert_eq!(s.storage.len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -230,14 +230,11 @@ fn execute_opcodes_10() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let calldata = hex::decode("a5f3c23b00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000004").unwrap();
|
let calldata = hex::decode("a5f3c23b00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000004").unwrap();
|
||||||
|
|
||||||
println!("LEN {:?}", calldata.len());
|
|
||||||
|
|
||||||
let mut s = Stack::new();
|
let mut s = Stack::new();
|
||||||
s.execute(&code, &calldata, true).unwrap();
|
s.execute(&code, &calldata, true).unwrap();
|
||||||
|
|
||||||
// assert_eq!(s.gas, 9999977752); // WIP correct sstore gas computation
|
assert_eq!(s.gas, 9999977752);
|
||||||
assert_eq!(s.gas, 9999979852);
|
|
||||||
assert_eq!(s.pc, 25);
|
assert_eq!(s.pc, 25);
|
||||||
assert_eq!(s.stack.len(), 1);
|
assert_eq!(s.stack.len(), 1);
|
||||||
assert_eq!(s.storage.len(), 1);
|
assert_eq!(s.storage.len(), 0);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user