use wasmer::wasmparser::Operator;
pub fn wasm_opcode_gas_schedule(operator: &Operator) -> u64 {
match operator {
Operator::I32Const { .. } | Operator::I64Const { .. } => 0,
Operator::Drop => 2,
Operator::Select => 3,
Operator::Nop
| Operator::Unreachable
| Operator::Loop { .. }
| Operator::Else
| Operator::If { .. } => 0,
Operator::Br { .. }
| Operator::BrTable { .. }
| Operator::Return
| Operator::Call { .. }
| Operator::CallIndirect { .. } => 2,
Operator::BrIf { .. } => 3,
Operator::GlobalGet { .. }
| Operator::GlobalSet { .. }
| Operator::LocalGet { .. }
| Operator::LocalSet { .. } => 3,
Operator::RefIsNull
| Operator::RefFunc { .. }
| Operator::RefNull { .. }
| Operator::ReturnCall { .. }
| Operator::ReturnCallIndirect { .. } => 2,
Operator::CatchAll
| Operator::Throw { .. }
| Operator::Rethrow { .. }
| Operator::Delegate { .. } => 2,
Operator::ElemDrop { .. } | Operator::DataDrop { .. } => 1,
Operator::TableInit { .. } => 2,
Operator::MemoryCopy { .. }
| Operator::MemoryFill { .. }
| Operator::TableCopy { .. }
| Operator::TableFill { .. } => 3,
Operator::I32Load { .. }
| Operator::I64Load { .. }
| Operator::I32Store { .. }
| Operator::I64Store { .. }
| Operator::I32Store8 { .. }
| Operator::I32Store16 { .. }
| Operator::I32Load8S { .. }
| Operator::I32Load8U { .. }
| Operator::I32Load16S { .. }
| Operator::I32Load16U { .. }
| Operator::I64Load8S { .. }
| Operator::I64Load8U { .. }
| Operator::I64Load16S { .. }
| Operator::I64Load16U { .. }
| Operator::I64Load32S { .. }
| Operator::I64Load32U { .. }
| Operator::I64Store8 { .. }
| Operator::I64Store16 { .. }
| Operator::I64Store32 { .. } => 3,
Operator::I32Add
| Operator::I32Sub
| Operator::I64Add
| Operator::I64Sub
| Operator::I64LtS
| Operator::I64LtU
| Operator::I64GtS
| Operator::I64GtU
| Operator::I64LeS
| Operator::I64LeU
| Operator::I64GeS
| Operator::I64GeU
| Operator::I32Eqz
| Operator::I32Eq
| Operator::I32Ne
| Operator::I32LtS
| Operator::I32LtU
| Operator::I32GtS
| Operator::I32GtU
| Operator::I32LeS
| Operator::I32LeU
| Operator::I32GeS
| Operator::I32GeU
| Operator::I64Eqz
| Operator::I64Eq
| Operator::I64Ne
| Operator::I32And
| Operator::I32Or
| Operator::I32Xor
| Operator::I64And
| Operator::I64Or
| Operator::I64Xor => 1,
Operator::I32Shl
| Operator::I32ShrU
| Operator::I32ShrS
| Operator::I32Rotl
| Operator::I32Rotr
| Operator::I64Shl
| Operator::I64ShrU
| Operator::I64ShrS
| Operator::I64Rotl
| Operator::I64Rotr => 2,
Operator::I32Mul | Operator::I64Mul => 3,
Operator::I32DivS
| Operator::I32DivU
| Operator::I32RemS
| Operator::I32RemU
| Operator::I64DivS
| Operator::I64DivU
| Operator::I64RemS
| Operator::I64RemU => 80,
Operator::I32Clz | Operator::I64Clz => 105,
Operator::I32WrapI64
| Operator::I64ExtendI32S
| Operator::I64ExtendI32U
| Operator::I32Extend8S
| Operator::I32Extend16S
| Operator::I64Extend8S
| Operator::I64Extend16S
| Operator::I64Extend32S => 3,
_ => 1,
}
}
pub const WASM_MEMORY_WRITE_PER64_BITS_COST: u64 = 3;
pub const WASM_MEMORY_READ_PER64_BITS_COST: u64 = 3;
pub const WASM_BYTE_CODE_PER_BYTE_COST: u64 = 3;
pub const fn wasm_memory_read_cost(len: usize) -> u64 {
let cost = ceil_div_8(len as u64).saturating_mul(WASM_MEMORY_READ_PER64_BITS_COST);
if cost == 0 {
return 1;
} cost
}
pub const fn wasm_memory_write_cost(len: usize) -> u64 {
let cost = ceil_div_8(len as u64).saturating_mul(WASM_MEMORY_WRITE_PER64_BITS_COST);
if cost == 0 {
return 1;
} cost
}
pub const fn ceil_div_8(l: u64) -> u64 {
l.saturating_add(7).saturating_div(8)
}
pub const BLOCKCHAIN_WRITE_PER_BYTE_COST: u64 = 30;
pub const MIN_RECP_SIZE: u64 = 4;
pub const MIN_CMDRECP_SIZE: u64 = 17;
pub fn tx_inclusion_cost(tx_size: usize, commands_len: usize) -> u64 {
let tx_size = tx_size as u64;
let min_receipt_size = minimum_receipt_size(commands_len);
let rw_key_cost = (
get_cost(ACCOUNT_STATE_KEY_LENGTH, 8)
.saturating_add(set_cost_write_new_value(8))
.saturating_add(set_cost_rehash(ACCOUNT_STATE_KEY_LENGTH))
)
.saturating_mul(5);
tx_size
.saturating_add(min_receipt_size)
.saturating_mul(BLOCKCHAIN_WRITE_PER_BYTE_COST)
.saturating_add(rw_key_cost)
}
pub const fn minimum_receipt_size(commands_len: usize) -> u64 {
MIN_RECP_SIZE.saturating_add(MIN_CMDRECP_SIZE.saturating_mul(commands_len as u64))
}
pub const fn blockchain_return_values_cost(data_len: usize) -> u64 {
(data_len as u64).saturating_mul(BLOCKCHAIN_WRITE_PER_BYTE_COST)
}
pub const fn blockchain_log_cost(topic_len: usize, val_len: usize) -> u64 {
let topic_len = topic_len as u64;
let val_len = val_len as u64;
let log_len = topic_len.saturating_add(val_len);
(ceil_div_8(log_len).saturating_mul(WASM_MEMORY_READ_PER64_BITS_COST))
.saturating_add(topic_len.saturating_mul(CRYPTO_SHA256_PER_BYTE))
.saturating_add(log_len.saturating_mul(BLOCKCHAIN_WRITE_PER_BYTE_COST))
}
pub const ACCOUNT_STATE_KEY_LENGTH: usize = 33;
pub const MPT_WRITE_PER_BYTE_COST: u64 = 2500;
pub const MPT_READ_PER_BYTE_COST: u64 = 50;
pub const MPT_TRAVERSE_PER_BYTE_COST: u64 = 20;
pub const MPT_REHASH_PER_BYTE_COST: u64 = 130;
pub const MPT_WRITE_REFUND_PROPORTION: u64 = 50;
pub const MPT_GET_CODE_DISCOUNT_PROPORTION: u64 = 50;
pub const fn get_cost(key_len: usize, value_len: usize) -> u64 {
let get_cost_1 = (value_len as u64).saturating_mul(MPT_READ_PER_BYTE_COST);
let get_cost_2 = (key_len as u64).saturating_mul(MPT_TRAVERSE_PER_BYTE_COST);
get_cost_1.saturating_add(get_cost_2)
}
pub const fn get_code_cost(code_len: usize) -> u64 {
get_cost(ACCOUNT_STATE_KEY_LENGTH, code_len)
.saturating_mul(MPT_GET_CODE_DISCOUNT_PROPORTION)
.saturating_div(100)
}
pub const fn set_cost_read_key(key_len: usize, value_len: usize) -> u64 {
get_cost(key_len, value_len)
}
#[allow(clippy::double_comparisons)]
pub const fn set_cost_delete_old_value(
key_len: usize,
old_val_len: usize,
new_val_len: usize,
) -> u64 {
let old_val_len = old_val_len as u64; let new_val_len = new_val_len as u64;
if (old_val_len > 0 || old_val_len == 0) && new_val_len > 0 {
old_val_len
.saturating_mul(MPT_WRITE_PER_BYTE_COST * MPT_WRITE_REFUND_PROPORTION)
.saturating_div(100)
} else if old_val_len > 0 && new_val_len == 0 {
((key_len as u64).saturating_add(old_val_len))
.saturating_mul(MPT_WRITE_PER_BYTE_COST * MPT_WRITE_REFUND_PROPORTION)
.saturating_div(100)
} else {
0
}
}
pub const fn set_cost_write_new_value(new_val_len: usize) -> u64 {
(new_val_len as u64).saturating_mul(MPT_WRITE_PER_BYTE_COST)
}
pub const fn set_cost_rehash(key_len: usize) -> u64 {
(key_len as u64).saturating_mul(MPT_REHASH_PER_BYTE_COST)
}
pub const fn contains_cost(key_len: usize) -> u64 {
(key_len as u64).saturating_mul(MPT_TRAVERSE_PER_BYTE_COST)
}
pub const CRYPTO_SHA256_PER_BYTE: u64 = 16;
pub const CRYPTO_KECCAK256_PER_BYTE: u64 = 16;
pub const CRYPTO_RIPEMD160_PER_BYTE: u64 = 16;
pub const fn crypto_verify_ed25519_signature_cost(msg_len: usize) -> u64 {
1_400_000_u64.saturating_add((msg_len as u64).saturating_mul(16_u64))
}