Skip to content

Commit cfc6518

Browse files
jakelangaxic
authored andcommitted
EEI: gas charges
Use YellowPaper-style gas fee names
1 parent 33a1dc5 commit cfc6518

File tree

2 files changed

+96
-5
lines changed

2 files changed

+96
-5
lines changed

src/eei.cpp

+81-5
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ namespace HeraVM {
154154
HERA_DEBUG << "getGasLeft\n";
155155

156156
static_assert(is_same<decltype(result.gasLeft), uint64_t>::value, "uint64_t type expected");
157+
158+
takeGas(GasSchedule::base);
159+
157160
return Literal(result.gasLeft);
158161
}
159162

@@ -164,6 +167,8 @@ namespace HeraVM {
164167

165168
storeUint160(msg.destination, resultOffset);
166169

170+
takeGas(GasSchedule::base);
171+
167172
return Literal();
168173
}
169174

@@ -175,6 +180,8 @@ namespace HeraVM {
175180

176181
evm_address address = loadUint160(addressOffset);
177182
evm_uint256be result;
183+
184+
takeGas(GasSchedule::balance);
178185
context->fn_table->get_balance(&result, context, &address);
179186
storeUint128(result, resultOffset);
180187

@@ -188,6 +195,8 @@ namespace HeraVM {
188195
HERA_DEBUG << "getBlockHash " << hex << number << " " << resultOffset << dec << "\n";
189196

190197
evm_uint256be blockhash;
198+
199+
takeGas(GasSchedule::blockhash);
191200
context->fn_table->get_block_hash(&blockhash, context, number);
192201
storeUint256(blockhash, resultOffset);
193202

@@ -196,6 +205,9 @@ namespace HeraVM {
196205

197206
if (import->base == Name("getCallDataSize")) {
198207
HERA_DEBUG << "callDataSize\n";
208+
209+
takeGas(GasSchedule::base);
210+
199211
return Literal(static_cast<uint32_t>(msg.input_size));
200212
}
201213

@@ -206,6 +218,13 @@ namespace HeraVM {
206218

207219
HERA_DEBUG << "callDataCopy " << hex << resultOffset << " " << dataOffset << " " << length << dec << "\n";
208220

221+
heraAssert(ffs(GasSchedule::copy) + (ffs(length) - 5) <= 64, "Gas charge overflow");
222+
heraAssert(
223+
numeric_limits<uint64_t>::max() - GasSchedule::verylow >= GasSchedule::copy * ((uint64_t(length) + 31) / 32),
224+
"Gas charge overflow"
225+
);
226+
takeGas(GasSchedule::verylow + GasSchedule::copy * ((uint64_t(length) + 31) / 32));
227+
209228
vector<uint8_t> input(msg.input_data, msg.input_data + msg.input_size);
210229
storeMemory(input, dataOffset, resultOffset, length);
211230

@@ -217,6 +236,7 @@ namespace HeraVM {
217236

218237
HERA_DEBUG << "getCaller " << hex << resultOffset << dec << "\n";
219238

239+
takeGas(GasSchedule::base);
220240
storeUint160(msg.sender, resultOffset);
221241

222242
return Literal();
@@ -227,6 +247,7 @@ namespace HeraVM {
227247

228248
HERA_DEBUG << "getCallValue " << hex << resultOffset << dec << "\n";
229249

250+
takeGas(GasSchedule::base);
230251
storeUint128(msg.value, resultOffset);
231252

232253
return Literal();
@@ -239,6 +260,12 @@ namespace HeraVM {
239260

240261
HERA_DEBUG << "codeCopy " << hex << resultOffset << " " << codeOffset << " " << length << dec << "\n";
241262

263+
heraAssert(ffs(GasSchedule::copy) + (ffs(length) - 5) <= 64, "Gas charge overflow");
264+
heraAssert(
265+
numeric_limits<uint64_t>::max() - GasSchedule::verylow >= GasSchedule::copy * ((uint64_t(length) + 31) / 32),
266+
"Gas charge overflow"
267+
);
268+
takeGas(GasSchedule::verylow + GasSchedule::copy * ((uint64_t(length) + 31) / 32));
242269
storeMemory(code, codeOffset, resultOffset, length);
243270

244271
return Literal();
@@ -247,6 +274,8 @@ namespace HeraVM {
247274
if (import->base == Name("getCodeSize")) {
248275
HERA_DEBUG << "getCodeSize\n";
249276

277+
takeGas(GasSchedule::base);
278+
250279
return Literal(static_cast<uint32_t>(code.size()));
251280
}
252281

@@ -262,8 +291,10 @@ namespace HeraVM {
262291
const uint8_t *code;
263292
size_t code_size = context->fn_table->get_code(&code, context, &address);
264293

294+
heraAssert(ffs(GasSchedule::copy) + (ffs(length) - 5) <= 64, "Gas charge overflow");
295+
heraAssert(numeric_limits<uint64_t>::max() - GasSchedule::extcode >= GasSchedule::copy * ((uint64_t(length) + 31) / 32), "Gas charge overflow");
296+
takeGas(GasSchedule::extcode + GasSchedule::copy * ((uint64_t(length) + 31) / 32));
265297
// NOTE: code will be freed by the callee (client)
266-
267298
// FIXME: optimise this so not vector needs to be created
268299
storeMemory(vector<uint8_t>(code, code + code_size), codeOffset, resultOffset, length);
269300

@@ -276,6 +307,7 @@ namespace HeraVM {
276307
HERA_DEBUG << "getExternalCodeSize " << hex << addressOffset << dec << "\n";
277308

278309
evm_address address = loadUint160(addressOffset);
310+
takeGas(GasSchedule::extcode);
279311
size_t code_size = context->fn_table->get_code(NULL, context, &address);
280312

281313
return Literal(static_cast<uint32_t>(code_size));
@@ -287,6 +319,8 @@ namespace HeraVM {
287319
HERA_DEBUG << "getBlockCoinbase " << hex << resultOffset << dec << "\n";
288320

289321
evm_tx_context tx_context;
322+
323+
takeGas(GasSchedule::base);
290324
context->fn_table->get_tx_context(&tx_context, context);
291325
storeUint160(tx_context.block_coinbase, resultOffset);
292326

@@ -299,6 +333,8 @@ namespace HeraVM {
299333
HERA_DEBUG << "getBlockDifficulty " << hex << offset << dec << "\n";
300334

301335
evm_tx_context tx_context;
336+
337+
takeGas(GasSchedule::base);
302338
context->fn_table->get_tx_context(&tx_context, context);
303339
storeUint256(tx_context.block_difficulty, offset);
304340

@@ -309,9 +345,12 @@ namespace HeraVM {
309345
HERA_DEBUG << "getBlockGasLimit\n";
310346

311347
evm_tx_context tx_context;
348+
349+
takeGas(GasSchedule::base);
312350
context->fn_table->get_tx_context(&tx_context, context);
313351

314352
static_assert(is_same<decltype(tx_context.block_gas_limit), int64_t>::value, "int64_t type expected");
353+
315354
return Literal(tx_context.block_gas_limit);
316355
}
317356

@@ -321,6 +360,8 @@ namespace HeraVM {
321360
HERA_DEBUG << "getTxGasPrice " << hex << valueOffset << dec << "\n";
322361

323362
evm_tx_context tx_context;
363+
364+
takeGas(GasSchedule::base);
324365
context->fn_table->get_tx_context(&tx_context, context);
325366
storeUint128(tx_context.tx_gas_price, valueOffset);
326367

@@ -335,7 +376,6 @@ namespace HeraVM {
335376
HERA_DEBUG << "log " << hex << dataOffset << " " << length << " " << numberOfTopics << dec << "\n";
336377

337378
heraAssert(!(msg.flags & EVM_STATIC), "\"log\" attempted in static mode");
338-
339379
heraAssert(numberOfTopics <= 4, "Too many topics specified");
340380

341381
evm_uint256be topics[numberOfTopics];
@@ -347,6 +387,12 @@ namespace HeraVM {
347387
vector<uint8_t> data(length);
348388
loadMemory(dataOffset, data, length);
349389

390+
heraAssert(ffs(length) + ffs(GasSchedule::logData) <= 64, "Gas charge overflow");
391+
heraAssert(
392+
numeric_limits<uint64_t>::max() - (GasSchedule::log + GasSchedule::logTopic * numberOfTopics) >= static_cast<uint64_t>(length) * GasSchedule::logData,
393+
"Gas charge overflow"
394+
);
395+
takeGas(GasSchedule::log + (length * GasSchedule::logData) + (GasSchedule::logTopic * numberOfTopics));
350396
context->fn_table->emit_log(context, &msg.destination, data.data(), length, topics, numberOfTopics);
351397

352398
return Literal();
@@ -356,19 +402,25 @@ namespace HeraVM {
356402
HERA_DEBUG << "getBlockNumber\n";
357403

358404
evm_tx_context tx_context;
405+
406+
takeGas(GasSchedule::base);
359407
context->fn_table->get_tx_context(&tx_context, context);
360408

361409
static_assert(is_same<decltype(tx_context.block_number), int64_t>::value, "int64_t type expected");
410+
362411
return Literal(tx_context.block_number);
363412
}
364413

365414
if (import->base == Name("getBlockTimestamp")) {
366415
HERA_DEBUG << "getBlockTimestamp\n";
367416

368417
evm_tx_context tx_context;
418+
419+
takeGas(GasSchedule::base);
369420
context->fn_table->get_tx_context(&tx_context, context);
370421

371422
static_assert(is_same<decltype(tx_context.block_timestamp), int64_t>::value, "int64_t type expected");
423+
372424
return Literal(tx_context.block_timestamp);
373425
}
374426

@@ -378,6 +430,8 @@ namespace HeraVM {
378430
HERA_DEBUG << "getTxOrigin " << hex << resultOffset << dec << "\n";
379431

380432
evm_tx_context tx_context;
433+
434+
takeGas(GasSchedule::base);
381435
context->fn_table->get_tx_context(&tx_context, context);
382436
storeUint160(tx_context.tx_origin, resultOffset);
383437

@@ -394,8 +448,8 @@ namespace HeraVM {
394448

395449
evm_uint256be path = loadUint256(pathOffset);
396450
evm_uint256be value = loadUint256(valueOffset);
397-
398451
evm_uint256be current;
452+
399453
context->fn_table->get_storage(&current, context, &msg.destination, &path);
400454

401455
// We do not need to take care about the delete case (gas refund), the client does it.
@@ -417,8 +471,9 @@ namespace HeraVM {
417471
HERA_DEBUG << "storageLoad " << hex << pathOffset << " " << resultOffset << dec << "\n";
418472

419473
evm_uint256be path = loadUint256(pathOffset);
420-
421474
evm_uint256be result;
475+
476+
takeGas(GasSchedule::storageLoad);
422477
context->fn_table->get_storage(&result, context, &msg.destination, &path);
423478

424479
storeUint256(result, resultOffset);
@@ -442,6 +497,9 @@ namespace HeraVM {
442497

443498
if (import->base == Name("getReturnDataSize")) {
444499
HERA_DEBUG << "getReturnDataSize\n";
500+
501+
takeGas(GasSchedule::base);
502+
445503
return Literal(static_cast<uint32_t>(lastReturnData.size()));
446504
}
447505

@@ -452,6 +510,7 @@ namespace HeraVM {
452510

453511
HERA_DEBUG << "returnDataCopy " << hex << dataOffset << " " << offset << " " << size << dec << "\n";
454512

513+
takeGas(GasSchedule::verylow);
455514
storeMemory(lastReturnData, offset, dataOffset, size);
456515

457516
return Literal();
@@ -482,7 +541,7 @@ namespace HeraVM {
482541
valueOffset = arguments[2].geti32();
483542
dataOffset = arguments[3].geti32();
484543
dataLength = arguments[4].geti32();
485-
544+
486545
call_message.sender = msg.destination;
487546
call_message.value = loadUint128(valueOffset);
488547
call_message.kind = (import->base == Name("callCode")) ? EVM_CALLCODE : EVM_CALL;
@@ -527,6 +586,13 @@ namespace HeraVM {
527586
}
528587

529588
evm_result call_result;
589+
590+
if (import->base == Name("call") && !context->fn_table->account_exists(context, &call_message.destination))
591+
takeGas(GasSchedule::callNewAccount);
592+
if (!isZeroUint256(call_message.value))
593+
takeGas(GasSchedule::valuetransfer);
594+
takeGas(call_message.gas);
595+
takeGas(GasSchedule::call);
530596
context->fn_table->call(&call_result, context, &call_message);
531597

532598
if (call_result.output_data) {
@@ -538,6 +604,9 @@ namespace HeraVM {
538604
if (call_result.release)
539605
call_result.release(&call_result);
540606

607+
/* Return unspent gas */
608+
result.gasLeft += call_result.gas_left;
609+
541610
switch (call_result.status_code) {
542611
case EVM_SUCCESS:
543612
return Literal(uint32_t(0));
@@ -583,7 +652,11 @@ namespace HeraVM {
583652
create_message.flags = 0;
584653

585654
evm_result create_result;
655+
656+
takeGas(create_message.gas);
657+
takeGas(GasSchedule::create);
586658
context->fn_table->call(&create_result, context, &create_message);
659+
587660
if (create_result.status_code == EVM_SUCCESS) {
588661
storeUint160(create_result.create_address, resultOffset);
589662
lastReturnData.clear();
@@ -615,6 +688,9 @@ namespace HeraVM {
615688

616689
evm_address address = loadUint160(addressOffset);
617690

691+
if (!context->fn_table->account_exists(context, &address))
692+
takeGas(GasSchedule::callNewAccount);
693+
takeGas(GasSchedule::selfdestruct);
618694
context->fn_table->selfdestruct(context, &msg.destination, &address);
619695

620696
return Literal();

src/eei.h

+15
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,23 @@ struct EthereumInterface : ShellExternalInterface {
116116
};
117117

118118
struct GasSchedule {
119+
static constexpr unsigned storageLoad = 200;
119120
static constexpr unsigned storageStoreCreate = 20000;
120121
static constexpr unsigned storageStoreChange = 5000;
122+
static constexpr unsigned log = 375;
123+
static constexpr unsigned logData = 8;
124+
static constexpr unsigned logTopic = 375;
125+
static constexpr unsigned create = 32000;
126+
static constexpr unsigned call = 700;
127+
static constexpr unsigned copy = 3;
128+
static constexpr unsigned blockhash = 800;
129+
static constexpr unsigned balance = 400;
130+
static constexpr unsigned base = 2;
131+
static constexpr unsigned verylow = 3;
132+
static constexpr unsigned extcode = 700;
133+
static constexpr unsigned selfdestruct = 5000;
134+
static constexpr unsigned valuetransfer = 9000;
135+
static constexpr unsigned callNewAccount = 25000;
121136
};
122137

123138
}

0 commit comments

Comments
 (0)