diff --git a/nimbus/p2p/executor.nim b/nimbus/p2p/executor.nim index 2b0cc6a3b..095852da7 100644 --- a/nimbus/p2p/executor.nim +++ b/nimbus/p2p/executor.nim @@ -26,16 +26,18 @@ proc processTransaction*(tx: Transaction, sender: EthAddress, vmState: BaseVMSta vmState.cumulativeGasUsed += result + let miner = vmState.getMinerAddress() + vmState.mutateStateDB: # miner fee let txFee = result.u256 * tx.gasPrice.u256 - db.addBalance(vmState.blockHeader.coinbase, txFee) + db.addBalance(miner, txFee) for deletedAccount in vmState.suicides: db.deleteAccount deletedAccount if fork >= FkSpurious: - vmState.touchedAccounts.incl(vmState.blockHeader.coinbase) + vmState.touchedAccounts.incl(miner) # EIP158/161 state clearing for account in vmState.touchedAccounts: if db.accountExists(account) and db.isEmptyAccount(account): @@ -93,6 +95,25 @@ const eth2 # FkIstanbul ] +proc calculateReward(fork: Fork, header: BlockHeader, body: BlockBody, vmState: BaseVMState) = + # PoA consensus engine have no reward for miner + if vmState.consensusEnginePoA: return + + let blockReward = blockRewards[fork] + var mainReward = blockReward + + for uncle in body.uncles: + var uncleReward = uncle.blockNumber.u256 + 8.u256 + uncleReward -= header.blockNumber.u256 + uncleReward = uncleReward * blockReward + uncleReward = uncleReward div 8.u256 + vmState.mutateStateDB: + db.addBalance(uncle.coinbase, uncleReward) + mainReward += blockReward div 32.u256 + + vmState.mutateStateDB: + db.addBalance(header.coinbase, mainReward) + proc processBlock*(chainDB: BaseChainDB, header: BlockHeader, body: BlockBody, vmState: BaseVMState): ValidationResult = var dbTx = chainDB.db.beginTransaction() defer: dbTx.dispose() @@ -125,25 +146,16 @@ proc processBlock*(chainDB: BaseChainDB, header: BlockHeader, body: BlockBody, v return ValidationResult.Error vmState.receipts[txIndex] = makeReceipt(vmState, fork) - let blockReward = blockRewards[fork] - var mainReward = blockReward if header.ommersHash != EMPTY_UNCLE_HASH: let h = chainDB.persistUncles(body.uncles) if h != header.ommersHash: debug "Uncle hash mismatch" return ValidationResult.Error - for uncle in body.uncles: - var uncleReward = uncle.blockNumber.u256 + 8.u256 - uncleReward -= header.blockNumber.u256 - uncleReward = uncleReward * blockReward - uncleReward = uncleReward div 8.u256 - vmState.mutateStateDB: - db.addBalance(uncle.coinbase, uncleReward) - mainReward += blockReward div 32.u256 + + calculateReward(fork, header, body, vmState) # Reward beneficiary vmState.mutateStateDB: - db.addBalance(header.coinbase, mainReward) if vmState.generateWitness: db.collectWitnessData() db.persist(ClearCache in vmState.flags) diff --git a/nimbus/vm_state.nim b/nimbus/vm_state.nim index f59d02b1b..2f99fa45a 100644 --- a/nimbus/vm_state.nim +++ b/nimbus/vm_state.nim @@ -7,8 +7,8 @@ import macros, strformat, tables, sets, options, - eth/common, - vm/interpreter/[vm_forks, gas_costs], + eth/[common, keys, rlp], nimcrypto/keccak, + vm/interpreter/[vm_forks, gas_costs], ./errors, ./constants, ./db/[db_chain, accounts_cache], ./utils, json, vm_types, vm/transaction_tracer, ./config, ../stateless/[multi_keys, witness_from_tree, witness_types] @@ -61,6 +61,48 @@ proc setupTxContext*(vmState: BaseVMState, origin: EthAddress, gasPrice: GasInt, vmState.chainDB.config.toFork(vmState.blockHeader.blockNumber) vmState.gasCosts = vmState.fork.forkToSchedule +proc consensusEnginePoA*(vmState: BaseVMState): bool = + let chainId = PublicNetwork(vmState.chainDB.config.chainId) + # PoA consensus engine have no reward for miner + result = chainId in {GoerliNet, RinkebyNet, KovanNet} + +proc getSignature(bytes: openArray[byte], output: var Signature): bool = + let sig = Signature.fromRaw(bytes) + if sig.isOk: + output = sig[] + return true + return false + +proc headerHashOriExtraData(vmState: BaseVMState): Hash256 = + var tmp = vmState.blockHeader + tmp.extraData.setLen(tmp.extraData.len-65) + result = keccak256.digest(rlp.encode(tmp)) + +proc getPubkey(sigRaw: openArray[byte], vmState: BaseVMState, output: var EthAddress): bool = + var sig: Signature + if sigRaw.getSignature(sig): + let headerHash = headerHashOriExtraData(vmState) + let pubkey = recover(sig, headerHash) + if pubkey.isOk: + output = pubkey[].toCanonicalAddress() + result = true + +proc getMinerAddress*(vmState: BaseVMState): EthAddress = + if not vmState.consensusEnginePoA: + return vmState.blockHeader.coinbase + + template data: untyped = + vmState.blockHeader.extraData + + let len = data.len + doAssert(len >= 65) + + var miner: EthAddress + if getPubkey(data.toOpenArray(len - 65, len-1), vmState, miner): + result = miner + else: + raise newException(ValidationError, "Could not derive miner address from header extradata") + proc updateBlockHeader*(vmState: BaseVMState, header: BlockHeader) = vmState.blockHeader = header vmState.touchedAccounts.clear()