Program Listing for File internal_operations.cuh#
↰ Return to documentation for file (src/internal_operations.cuh
)
// cuEVM: CUDA Ethereum Virtual Machine implementation
// Copyright 2023 Stefan-Dan Ciocirlan (SBIP - Singapore Blockchain Innovation Programme)
// Author: Stefan-Dan Ciocirlan
// Data: 2023-11-30
// SPDX-License-Identifier: MIT
#ifndef _INTERNAL_OP_H_
#define _INTERNAL_OP_H_
#include "utils.h"
#include "stack.cuh"
#include "block.cuh"
#include "state.cuh"
#include "message.cuh"
#include "logs.cuh"
template <class params>
class internal_operations
{
public:
typedef arith_env_t<params> arith_t;
typedef typename arith_t::bn_t bn_t;
typedef stack_t<params> stack_t;
typedef block_t<params> block_t;
typedef touch_state_t<params> touch_state_t;
typedef memory_t<params> memory_t;
typedef transaction_t<params> transaction_t;
typedef message_t<params> message_t;
typedef log_state_t<params> log_state_t;
static const uint32_t HASH_BYTES = 32;
__host__ __device__ __forceinline__ static void operation_MLOAD(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
memory_t &memory)
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_VERY_LOW);
bn_t memory_offset;
stack.pop(memory_offset, error_code);
bn_t length;
cgbn_set_ui32(arith._env, length, arith_t::BYTES);
memory.grow_cost(
memory_offset,
length,
gas_used,
error_code);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
uint8_t *data;
data = memory.get(
memory_offset,
length,
error_code);
bn_t value;
arith.cgbn_from_memory(
value,
data);
stack.push(value, error_code);
pc = pc + 1;
}
}
__host__ __device__ __forceinline__ static void operation_MSTORE(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
memory_t &memory)
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_VERY_LOW);
bn_t memory_offset;
stack.pop(memory_offset, error_code);
bn_t value;
stack.pop(value, error_code);
bn_t length;
cgbn_set_ui32(arith._env, length, arith_t::BYTES);
if (error_code == ERR_NONE)
{
memory.grow_cost(
memory_offset,
length,
gas_used,
error_code);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
uint8_t data[arith_t::BYTES];
size_t available_size;
arith.memory_from_cgbn(
&(data[0]),
value);
available_size = arith_t::BYTES;
memory.set(
&(data[0]),
memory_offset,
length,
available_size,
error_code);
pc = pc + 1;
}
}
}
__host__ __device__ __forceinline__ static void operation_MSTORE8(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
memory_t &memory)
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_VERY_LOW);
bn_t memory_offset;
stack.pop(memory_offset, error_code);
bn_t value;
stack.pop(value, error_code);
bn_t length;
cgbn_set_ui32(arith._env, length, 1);
if (error_code == ERR_NONE)
{
memory.grow_cost(
memory_offset,
length,
gas_used,
error_code);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
uint8_t data[arith_t::BYTES];
size_t available_size;
arith.memory_from_cgbn(
&(data[0]),
value);
available_size = 1;
memory.set(
&(data[arith_t::BYTES - 1]),
memory_offset,
length,
available_size,
error_code);
pc = pc + 1;
}
}
}
__host__ __device__ __forceinline__ static void operation_SLOAD(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
touch_state_t &touch_state,
message_t &message)
{
// cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_ZERO);
bn_t key;
stack.pop(key, error_code);
if (error_code == ERR_NONE)
{
bn_t storage_address;
message.get_storage_address(storage_address);
touch_state.charge_gas_access_storage(
storage_address,
key,
gas_used);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
bn_t value;
touch_state.get_value(
storage_address,
key,
value);
stack.push(value, error_code);
pc = pc + 1;
}
}
}
__host__ __device__ __forceinline__ static void operation_SSTORE(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
bn_t &gas_refund,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
touch_state_t &touch_state,
message_t &message)
{
// only if is not a static call
if (message.get_static_env() == 0)
{
// cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_ZERO);
bn_t gas_left;
cgbn_sub(arith._env, gas_left, gas_limit, gas_used);
if (cgbn_compare_ui32(arith._env, gas_left, GAS_STIPEND) < 0)
{
error_code = ERR_OUT_OF_GAS;
}
else
{
bn_t key;
stack.pop(key, error_code);
bn_t value;
stack.pop(value, error_code);
if (error_code == ERR_NONE)
{
bn_t storage_address;
message.get_storage_address(storage_address);
touch_state.charge_gas_set_storage(
storage_address,
key,
value,
gas_used,
gas_refund);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
touch_state.set_value(
storage_address,
key,
value);
pc = pc + 1;
}
}
}
}
else
{
error_code = ERROR_STATIC_CALL_CONTEXT_SSTORE;
}
}
__host__ __device__ __forceinline__ static void operation_JUMP(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
jump_destinations_t &jumpdest)
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_MID);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
bn_t destination;
stack.pop(destination, error_code);
size_t destination_s;
int32_t overflow;
overflow = arith.size_t_from_cgbn(destination_s, destination);
if (error_code == ERR_NONE)
{
// if is not a valid jump destination
if (
(overflow == 1) ||
(jumpdest.has(destination_s) == 0))
{
error_code = ERR_INVALID_JUMP_DESTINATION;
}
else
{
pc = destination_s;
}
}
}
}
__host__ __device__ __forceinline__ static void operation_JUMPI(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
jump_destinations_t &jumpdest)
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_HIGH);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
bn_t destination;
stack.pop(destination, error_code);
bn_t condition;
stack.pop(condition, error_code);
if (error_code == ERR_NONE)
{
if (cgbn_compare_ui32(arith._env, condition, 0) != 0)
{
size_t destination_s;
int32_t overflow;
overflow = arith.size_t_from_cgbn(destination_s, destination);
// if is not a valid jump destination
if (
(overflow == 1) ||
(jumpdest.has(destination_s) == 0))
{
error_code = ERR_INVALID_JUMP_DESTINATION;
}
else
{
pc = destination_s;
}
}
else
{
pc = pc + 1;
}
}
}
}
__host__ __device__ __forceinline__ static void operation_PC(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack)
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_BASE);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
bn_t pc_bn;
cgbn_set_ui32(arith._env, pc_bn, pc);
stack.push(pc_bn, error_code);
pc = pc + 1;
}
}
__host__ __device__ __forceinline__ static void operation_MSIZE(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
memory_t &memory)
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_BASE);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
bn_t size;
size_t size_s;
size_s = memory.size();
arith.cgbn_from_size_t(
size,
size_s);
stack.push(size, error_code);
pc = pc + 1;
}
}
__host__ __device__ __forceinline__ static void operation_GAS(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack)
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_BASE);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
bn_t gas_left;
cgbn_sub(arith._env, gas_left, gas_limit, gas_used);
stack.push(gas_left, error_code);
pc = pc + 1;
}
}
__host__ __device__ __forceinline__ static void operation_JUMPDEST(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc)
{
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_JUMP_DEST);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
pc = pc + 1;
}
}
__host__ __device__ __forceinline__ static void operation_LOGX(
arith_t &arith,
bn_t &gas_limit,
bn_t &gas_used,
uint32_t &error_code,
uint32_t &pc,
stack_t &stack,
memory_t &memory,
message_t &message,
log_state_t &log_state,
uint8_t &opcode)
{
if (message.get_static_env())
{
error_code = ERROR_STATIC_CALL_CONTEXT_LOG;
}
else
{
uint8_t log_index = opcode & 0x0F;
cgbn_add_ui32(arith._env, gas_used, gas_used, GAS_LOG);
bn_t memory_offset;
stack.pop(memory_offset, error_code);
bn_t length;
stack.pop(length, error_code);
bn_t topics[4];
bn_t dynamic_gas;
cgbn_mul_ui32(arith._env, dynamic_gas, length, GAS_LOG_DATA);
cgbn_add(arith._env, gas_used, gas_used, dynamic_gas);
bn_t topic_gas;
cgbn_set_ui32(arith._env, topic_gas, GAS_LOG_TOPIC);
cgbn_mul_ui32(arith._env, topic_gas, topic_gas, log_index);
cgbn_add(arith._env, gas_used, gas_used, topic_gas);
uint32_t no_topics = log_index;
for (uint32_t idx = 0; idx < no_topics; idx++)
{
stack.pop(topics[idx], error_code);
}
for (uint32_t idx = no_topics; idx < 4; idx++)
{
cgbn_set_ui32(arith._env, topics[idx], 0);
}
if (error_code == ERR_NONE)
{
memory.grow_cost(
memory_offset,
length,
gas_used,
error_code);
if (arith.has_gas(gas_limit, gas_used, error_code))
{
SHARED_MEMORY data_content_t record;
record.data = memory.get(
memory_offset,
length,
error_code);
arith.size_t_from_cgbn(record.size, length);
bn_t address;
message.get_contract_address(address);
log_state.push(
address,
record,
topics[0],
topics[1],
topics[2],
topics[3],
no_topics);
pc = pc + 1;
}
}
}
}
};
#endif