diff --git a/CHANGELOG.md b/CHANGELOG.md index 3640fa99f..0ee72655c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#2144](https://github.com/NibiruChain/nibiru/pull/2144) - feat(token-registry): Implement strongly typed Nibiru Token Registry and generation command - [#2145](https://github.com/NibiruChain/nibiru/pull/2145) - chore(token-registry): add xNIBI Astrovault LST to registry - [#2147](https://github.com/NibiruChain/nibiru/pull/2147) - fix(simapp): manually add x/vesting Cosmos-SDK module types to the codec in simulation tests since they are expected by default +- [#2151](https://github.com/NibiruChain/nibiru/pull/2151) - feat(evm): randao support for evm - [#2152](https://github.com/NibiruChain/nibiru/pull/2152) - fix(precompile): consume gas for precompile calls regardless of error #### Nibiru EVM | Before Audit 2 - 2024-12-06 diff --git a/x/evm/embeds/artifacts/contracts/TestRandom.sol/TestRandom.json b/x/evm/embeds/artifacts/contracts/TestRandom.sol/TestRandom.json new file mode 100644 index 000000000..7ce4989f4 --- /dev/null +++ b/x/evm/embeds/artifacts/contracts/TestRandom.sol/TestRandom.json @@ -0,0 +1,24 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "TestRandom", + "sourceName": "contracts/TestRandom.sol", + "abi": [ + { + "inputs": [], + "name": "getRandom", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b5060b58061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063aacc5a1714602d575b600080fd5b60336047565b604051603e91906066565b60405180910390f35b600044905090565b6000819050919050565b606081604f565b82525050565b6000602082019050607960008301846059565b9291505056fea264697066735822122021d2de67a73b1cbeefb199f56299f80c5f7aeb23a677b105ef78f6880f75491464736f6c63430008180033", + "deployedBytecode": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063aacc5a1714602d575b600080fd5b60336047565b604051603e91906066565b60405180910390f35b600044905090565b6000819050919050565b606081604f565b82525050565b6000602082019050607960008301846059565b9291505056fea264697066735822122021d2de67a73b1cbeefb199f56299f80c5f7aeb23a677b105ef78f6880f75491464736f6c63430008180033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/x/evm/embeds/contracts/TestRandom.sol b/x/evm/embeds/contracts/TestRandom.sol new file mode 100644 index 000000000..3f5f33a57 --- /dev/null +++ b/x/evm/embeds/contracts/TestRandom.sol @@ -0,0 +1,10 @@ +// contracts/TestERC20.sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +contract TestRandom { + + function getRandom() public view returns (uint256) { + return block.prevrandao; + } +} diff --git a/x/evm/embeds/embeds.go b/x/evm/embeds/embeds.go index 45a130459..1514e0dcc 100644 --- a/x/evm/embeds/embeds.go +++ b/x/evm/embeds/embeds.go @@ -41,6 +41,8 @@ var ( testInfiniteRecursionERC20Json []byte //go:embed artifacts/contracts/TestERC20TransferWithFee.sol/TestERC20TransferWithFee.json testERC20TransferWithFee []byte + //go:embed artifacts/contracts/TestRandom.sol/TestRandom.json + testRandom []byte ) var ( @@ -134,6 +136,11 @@ var ( Name: "TestERC20TransferWithFee.sol", EmbedJSON: testERC20TransferWithFee, } + // SmartContract_TestRandom is a test contract which tests random function + SmartContract_TestRandom = CompiledEvmContract{ + Name: "TestRandom.sol", + EmbedJSON: testRandom, + } ) func init() { @@ -150,6 +157,7 @@ func init() { SmartContract_TestPrecompileSelfCallRevert.MustLoad() SmartContract_TestInfiniteRecursionERC20.MustLoad() SmartContract_TestERC20TransferWithFee.MustLoad() + SmartContract_TestRandom.MustLoad() } type CompiledEvmContract struct { diff --git a/x/evm/embeds/embeds_test.go b/x/evm/embeds/embeds_test.go index d7e7686b2..cf1f0177f 100644 --- a/x/evm/embeds/embeds_test.go +++ b/x/evm/embeds/embeds_test.go @@ -21,5 +21,6 @@ func TestLoadContracts(t *testing.T) { embeds.SmartContract_TestERC20TransferThenPrecompileSend.MustLoad() embeds.SmartContract_TestInfiniteRecursionERC20.MustLoad() embeds.SmartContract_TestERC20TransferWithFee.MustLoad() + embeds.SmartContract_TestRandom.MustLoad() }) } diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 0b36e3a61..f9a279eaf 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -3,6 +3,7 @@ package keeper import ( "context" + "encoding/binary" "encoding/json" "fmt" "math/big" @@ -121,6 +122,10 @@ func (k *Keeper) NewEVM( tracer vm.EVMLogger, stateDB vm.StateDB, ) *vm.EVM { + pseudoRandomBytes := make([]byte, 8) + binary.BigEndian.PutUint64(pseudoRandomBytes, uint64(ctx.BlockHeader().Time.UnixNano())) + pseudoRandom := crypto.Keccak256Hash(append(pseudoRandomBytes, ctx.BlockHeader().LastCommitHash...)) + blockCtx := vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, @@ -131,7 +136,7 @@ func (k *Keeper) NewEVM( Time: big.NewInt(ctx.BlockHeader().Time.Unix()), Difficulty: big.NewInt(0), // unused. Only required in PoW context BaseFee: evmConfig.BaseFeeWei, - Random: nil, // not supported + Random: &pseudoRandom, } txCtx := core.NewEVMTxContext(msg) diff --git a/x/evm/keeper/random_test.go b/x/evm/keeper/random_test.go new file mode 100644 index 000000000..606c224cc --- /dev/null +++ b/x/evm/keeper/random_test.go @@ -0,0 +1,35 @@ +// Copyright (c) 2023-2024 Nibi, Inc. +package keeper_test + +import ( + "time" + + "github.com/NibiruChain/nibiru/v2/x/evm/embeds" + "github.com/NibiruChain/nibiru/v2/x/evm/evmtest" +) + +// TestRandom tests the random value generation within the EVM. +func (s *Suite) TestRandom() { + deps := evmtest.NewTestDeps() + deployResp, err := evmtest.DeployContract(&deps, embeds.SmartContract_TestRandom) + s.Require().NoError(err) + randomContractAddr := deployResp.ContractAddr + + // highjacked LoadERC20BigInt method as it perfectly fits the need of this test + random1, err := deps.EvmKeeper.LoadERC20BigInt( + deps.Ctx, embeds.SmartContract_TestRandom.ABI, randomContractAddr, "getRandom", + ) + s.Require().NoError(err) + s.Require().NotNil(random1) + s.Require().NotZero(random1.Int64()) + + // Update block time to check that random changes + deps.Ctx = deps.Ctx.WithBlockTime(deps.Ctx.BlockTime().Add(1 * time.Second)) + random2, err := deps.EvmKeeper.LoadERC20BigInt( + deps.Ctx, embeds.SmartContract_TestRandom.ABI, randomContractAddr, "getRandom", + ) + s.Require().NoError(err) + s.Require().NotNil(random1) + s.Require().NotZero(random2.Int64()) + s.Require().NotEqual(random1, random2) +}