Skip to content
This repository has been archived by the owner on Nov 18, 2022. It is now read-only.

feat: subtract IntrinsicGas before executing a transaction #160

Merged
merged 7 commits into from
Jun 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 31 additions & 18 deletions c/polyjuice.h
Original file line number Diff line number Diff line change
Expand Up @@ -1356,6 +1356,17 @@ int run_polyjuice() {
return ret;
}

/* Ensure the transaction has more gas than the basic tx fee. */
uint64_t min_gas;
ret = intrinsic_gas(&msg, is_create(msg.kind), &min_gas);
if (ret != 0) {
return ret;
}
if ((uint64_t)msg.gas < min_gas) {
debug_print_int("Insufficient gas limit, should exceed", min_gas);
return ERROR_INSUFFICIENT_GAS_LIMIT;
}

/* Load: validator_code_hash, hash_type, g_sudt_id */
ret = load_globals(&context, context.transaction_context.to_id);
if (ret != 0) {
Expand All @@ -1371,27 +1382,41 @@ int run_polyjuice() {
uint8_t evm_memory[MAX_EVM_MEMORY_SIZE];
init_evm_memory(evm_memory, MAX_EVM_MEMORY_SIZE);

/* init EVM execution result */
struct evmc_result res;
memset(&res, 0, sizeof(evmc_result));
res.status_code = EVMC_FAILURE; // Generic execution failure
res.status_code = EVMC_FAILURE; // Generic execution failure
debug_print_int("[run_polyjuice] initial gas limit", msg.gas);
int64_t initial_gas = msg.gas;
msg.gas -= min_gas; // subtract IntrinsicGas

int ret_handle_message = handle_message(&context, UINT32_MAX, UINT32_MAX, NULL, &msg, &res);
uint64_t gas_used = (uint64_t)(msg.gas - res.gas_left);

// debug_print evmc_result.output_data if the execution failed
if (res.status_code != 0) {
debug_print_int("evmc_result.output_size", res.output_size);
// The output contains data coming from REVERT opcode
debug_print_data("evmc_result.output_data:", res.output_data,
res.output_size > 100 ? 100 : res.output_size);

// record the used memory of a failed transaction
uint32_t used_memory;
memcpy(&used_memory, res.padding, sizeof(uint32_t));
debug_print_int("[run_polyjuice] used_memory(Bytes)", used_memory);
}


debug_print_int("[run_polyjuice] gas left", res.gas_left);
uint64_t gas_used =
(uint64_t)(res.gas_left <= 0 ? initial_gas : initial_gas - res.gas_left);
TheWaWaR marked this conversation as resolved.
Show resolved Hide resolved
debug_print_int("[run_polyjuice] gas_used", gas_used);

/* emit POLYJUICE_SYSTEM log to Godwoken */
ret = emit_evm_result_log(&context, gas_used, res.status_code);
if (ret != 0) {
ckb_debug("emit_evm_result_log failed");
return clean_evmc_result_and_return(&res, ret);
}

/* Godwoken syscall: SET_RETURN_DATA */
ret = context.sys_set_program_return_data(&context,
(uint8_t *)res.output_data,
res.output_size);
Expand All @@ -1405,26 +1430,12 @@ int run_polyjuice() {
return clean_evmc_result_and_return(&res, ret_handle_message);
}

uint32_t used_memory;
memcpy(&used_memory, res.padding, sizeof(uint32_t));
debug_print_int("[run_polyjuice] used_memory(Bytes)", used_memory);

/* Handle transaction fee */
if (res.gas_left < 0) {
ckb_debug("gas not enough");
return clean_evmc_result_and_return(&res, -1);
}
if (msg.gas < res.gas_left) {
debug_print_int("msg.gas", msg.gas);
debug_print_int("res.gas_left", res.gas_left);
ckb_debug("unreachable!");
return clean_evmc_result_and_return(&res, -1);
}

debug_print_int("gas limit", msg.gas);
debug_print_int("gas left", res.gas_left);
uint256_t fee_u256 = calculate_fee(gas_price, gas_used);

gw_reg_addr_t sender_addr = new_reg_addr(msg.sender.bytes);
ret = sudt_pay_fee(&context, g_sudt_id, /* g_sudt_id must already exists */
sender_addr, fee_u256);
Expand All @@ -1433,10 +1444,12 @@ int run_polyjuice() {
return clean_evmc_result_and_return(&res, ret);
}

/* finalize state */
ckb_debug("[run_polyjuice] finalize");
ret = gw_finalize(&context);
if (ret != 0) {
return clean_evmc_result_and_return(&res, ret);
}

return clean_evmc_result_and_return(&res, 0);
}
1 change: 1 addition & 0 deletions c/polyjuice_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@

#define ERROR_TOTAL_SUPPLY_OF_ANY_SUDT -91
#define ERROR_CONTRACT_ADDRESS_COLLISION -92
#define ERROR_INSUFFICIENT_GAS_LIMIT -93

#endif // POLYJUICE_ERRORS_H
11 changes: 10 additions & 1 deletion c/polyjuice_globals.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef POLYJUICE_GLOBALS_H
#define POLYJUICE_GLOBALS_H

#define POLYJUICE_VERSION "v1.1.6-beta"
#define POLYJUICE_VERSION "v1.2.0"

#define ETH_ADDRESS_LEN 20

Expand Down Expand Up @@ -38,4 +38,13 @@ static evmc_address g_tx_origin = {0};
static uint8_t g_script_code_hash[32] = {0};
static uint8_t g_script_hash_type = 0xff;

/* Minimal gas of a normal transaction*/
#define MIN_TX_GAS 21000
/* Minimal gas of a transaction that creates a contract */
#define MIN_CONTRACT_CREATION_TX_GAS 53000
/* Gas per byte of non zero data attached to a transaction */
#define DATA_NONE_ZERO_TX_GAS 16
/* Gas per byte of data attached to a transaction */
#define DATA_ZERO_TX_GAS 4

#endif // POLYJUICE_GLOBALS_H
38 changes: 38 additions & 0 deletions c/polyjuice_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,4 +318,42 @@ bool is_evmc_error(int error_code) {
return error_code >= 1 && error_code <= 16;
}

/**
* @brief computes the 'intrinsic gas' for a message with the given data
*
* @param msg evmc_message: transaction message
* @param is_create bool: isContractCreation
* @param min_gas the result of calculated intrinsic gas
* @return int
*/
int intrinsic_gas(const evmc_message *msg, const bool is_create,
uint64_t *min_gas) {
// Set the starting gas for the raw transaction
*min_gas = is_create ? MIN_CONTRACT_CREATION_TX_GAS : MIN_TX_GAS;

// Bump the required gas by the size of transactional data
if (msg->input_size > 0) {
// Zero and non-zero bytes are priced differently
uint64_t non_zero_bytes = 0;
for (size_t i = 0; i < msg->input_size; i++) {
if (*(msg->input_data + i) != 0)
non_zero_bytes++;
}

// Make sure we don't exceed uint64 for all data combinations
if ((UINT64_MAX - *min_gas) / DATA_NONE_ZERO_TX_GAS < non_zero_bytes) {
magicalne marked this conversation as resolved.
Show resolved Hide resolved
return ERROR_INSUFFICIENT_GAS_LIMIT;
}
*min_gas += non_zero_bytes * DATA_NONE_ZERO_TX_GAS;

uint64_t zero_bytes = msg->input_size - non_zero_bytes;
if ((UINT64_MAX - *min_gas) / DATA_ZERO_TX_GAS < zero_bytes) {
return ERROR_INSUFFICIENT_GAS_LIMIT;
}
*min_gas += zero_bytes * DATA_ZERO_TX_GAS;
}

return 0;
}

#endif // POLYJUICE_UTILS_H
2 changes: 1 addition & 1 deletion polyjuice-tests/src/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ pub fn simple_storage_get(
let block_info = new_block_info(addr, block_number, block_number);
let input = hex::decode("6d4ce63c").unwrap();
let args = PolyjuiceArgsBuilder::default()
.gas_limit(21000)
.gas_limit(30000)
.gas_price(1)
.value(0)
.input(&input)
Expand Down
2 changes: 1 addition & 1 deletion polyjuice-tests/src/test_cases/account_already_exists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn test_account_already_exists() {
CREATOR_ACCOUNT_ID,
from_id,
SS_INIT_CODE,
50000,
77659,
0,
block_producer_id,
0,
Expand Down
4 changes: 2 additions & 2 deletions polyjuice-tests/src/test_cases/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ fn test_get_contract_code() {
let block_info = new_block_info(block_producer_id.clone(), block_number, block_number);
let input = hex::decode("c59083f5").expect("createMemoryArray function");
let args = PolyjuiceArgsBuilder::default()
.gas_limit(10000)
.gas_limit(30297)
.gas_price(1)
.value(0)
.input(&input)
Expand Down Expand Up @@ -81,7 +81,7 @@ fn test_get_contract_code() {
let block_info = new_block_info(block_producer_id, block_number, block_number);
let input = hex::decode("ea879634").expect("getCode function");
let args = PolyjuiceArgsBuilder::default()
.gas_limit(10000)
.gas_limit(25439)
.gas_price(1)
.value(0)
.input(&input)
Expand Down
6 changes: 3 additions & 3 deletions polyjuice-tests/src/test_cases/address_collision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn create_address_collision_overwrite() -> Result<()> {
CREATOR_ACCOUNT_ID,
from_id,
INIT_CODE,
122000,
170000,
0,
block_producer_id,
1,
Expand Down Expand Up @@ -91,7 +91,7 @@ fn create_address_collision_duplicate() {
CREATOR_ACCOUNT_ID,
eoa_id,
SS_CODE,
122000,
130000,
0,
block_producer_id.clone(),
1,
Expand All @@ -106,7 +106,7 @@ fn create_address_collision_duplicate() {
CREATOR_ACCOUNT_ID,
from_id,
INIT_CODE,
122000,
130000,
0,
block_producer_id,
1,
Expand Down
2 changes: 1 addition & 1 deletion polyjuice-tests/src/test_cases/beacon_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn test_beacon_proxy() {
helper::CREATOR_ACCOUNT_ID,
from_id,
CONTRACT_CODE,
80000,
233000,
0,
block_producer.to_owned(),
block_number,
Expand Down
4 changes: 2 additions & 2 deletions polyjuice-tests/src/test_cases/call_multiple_times.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn test_call_multiple_times() {
let block_producer_id = crate::helper::create_block_producer(&mut state);

let from_eth_address = [1u8; 20];
let (from_id, _) = create_eth_eoa_account(&mut state, &from_eth_address, 300000u64.into());
let (from_id, _) = create_eth_eoa_account(&mut state, &from_eth_address, 500000u64.into());

// Deploy two SimpleStorage
let mut block_number = 1;
Expand Down Expand Up @@ -126,7 +126,7 @@ fn test_call_multiple_times() {
))
.unwrap();
let args = PolyjuiceArgsBuilder::default()
.gas_limit(200000)
.gas_limit(163263)
.gas_price(1)
.value(0)
.input(&input)
Expand Down
14 changes: 7 additions & 7 deletions polyjuice-tests/src/test_cases/contract_call_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn test_contract_call_contract() {

let from_eth_address = [1u8; 20];
let (from_id, _from_script_hash) =
helper::create_eth_eoa_account(&mut state, &from_eth_address, 200000u64.into());
helper::create_eth_eoa_account(&mut state, &from_eth_address, 400000u64.into());

// Deploy SimpleStorage
let mut block_number = 1;
Expand All @@ -34,7 +34,7 @@ fn test_contract_call_contract() {
CREATOR_ACCOUNT_ID,
from_id,
SS_INIT_CODE,
122000,
77659,
0,
block_producer.clone(),
block_number,
Expand All @@ -58,7 +58,7 @@ fn test_contract_call_contract() {
CREATOR_ACCOUNT_ID,
from_id,
input.as_str(),
122000,
84209,
0,
block_producer.clone(),
block_number,
Expand Down Expand Up @@ -97,7 +97,7 @@ fn test_contract_call_contract() {
hex::decode("28cc7b2500000000000000000000000000000000000000000000000000000000000000de")
.unwrap(); // 0xde = 222
let args = PolyjuiceArgsBuilder::default()
.gas_limit(51000)
.gas_limit(71000)
.gas_price(1)
.value(0)
.input(&input)
Expand Down Expand Up @@ -160,7 +160,7 @@ fn test_contract_call_non_exists_contract() {
CREATOR_ACCOUNT_ID,
from_id,
CALL_NON_EXISTS_INIT_CODE,
122000,
1220000,
0,
block_producer_id.clone(),
block_number,
Expand All @@ -187,7 +187,7 @@ fn test_contract_call_non_exists_contract() {
hex::decode("56c94e70000000000000000000000000ffffffffffffffffffffffffffffffffffffffff")
.unwrap();
let args = PolyjuiceArgsBuilder::default()
.gas_limit(51000)
.gas_limit(73000)
.gas_price(1)
.value(0)
.input(&input)
Expand Down Expand Up @@ -227,7 +227,7 @@ fn test_contract_call_non_exists_contract() {
let input = hex::decode(format!("56c94e70{}", hex::encode(eoa_ethabi_addr))).unwrap();
println!("{}", hex::encode(&input));
let args = PolyjuiceArgsBuilder::default()
.gas_limit(51000)
.gas_limit(73000)
.gas_price(1)
.value(0)
.input(&input)
Expand Down
4 changes: 2 additions & 2 deletions polyjuice-tests/src/test_cases/contract_create_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn test_contract_create_contract() {
CREATOR_ACCOUNT_ID,
from_id,
INIT_CODE,
122000,
170000,
0,
block_producer_id.clone(),
1,
Expand Down Expand Up @@ -81,7 +81,7 @@ fn test_contract_create_contract() {
let block_info = new_block_info(block_producer_id, 2, 0);
let input = hex::decode("6d4ce63c").unwrap();
let args = PolyjuiceArgsBuilder::default()
.gas_limit(21000)
.gas_limit(23000)
.gas_price(1)
.value(0)
.input(&input)
Expand Down
6 changes: 3 additions & 3 deletions polyjuice-tests/src/test_cases/delegatecall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn test_delegatecall() {

let from_eth_address = [1u8; 20];
let (from_id, _from_script_hash) =
helper::create_eth_eoa_account(&mut state, &from_eth_address, 280000u64.into());
helper::create_eth_eoa_account(&mut state, &from_eth_address, 400000u64.into());

// Deploy SimpleStorage
let mut block_number = 1;
Expand All @@ -33,7 +33,7 @@ fn test_delegatecall() {
CREATOR_ACCOUNT_ID,
from_id,
SS_INIT_CODE,
122000,
120000,
0,
block_producer.clone(),
block_number,
Expand All @@ -53,7 +53,7 @@ fn test_delegatecall() {
CREATOR_ACCOUNT_ID,
from_id,
INIT_CODE,
122000,
132000,
0,
block_producer.clone(),
block_number,
Expand Down
Loading