From 6137f79f726e8ec6a282ee0ca4ed45c05020ed4c Mon Sep 17 00:00:00 2001 From: Wei-Ning Huang Date: Thu, 18 Oct 2018 13:12:16 +0800 Subject: core: vm: implement RAND opcode support DEXON has a built-in on chain random oracle that allow one to retrieve a random variable. Add a new opcode `RAND` to load the random variable onto the stack. --- core/vm/evm.go | 1 + core/vm/instructions.go | 22 ++++++++++++++++++++++ core/vm/jump_table.go | 6 ++++++ core/vm/opcodes.go | 3 +++ 4 files changed, 32 insertions(+) (limited to 'core/vm') diff --git a/core/vm/evm.go b/core/vm/evm.go index e22acb81c..be2dabcf5 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -90,6 +90,7 @@ type Context struct { GasLimit uint64 // Provides information for GASLIMIT BlockNumber *big.Int // Provides information for NUMBER Time *big.Int // Provides information for TIME + Randomness []byte // Provides information for RAND Difficulty *big.Int // Provides information for DIFFICULTY } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 349f407a2..de0fcaeb6 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -17,6 +17,7 @@ package vm import ( + "encoding/binary" "errors" "fmt" "math/big" @@ -24,6 +25,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/common/math" "github.com/dexon-foundation/dexon/core/types" + "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/params" "golang.org/x/crypto/sha3" ) @@ -404,6 +406,26 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory return nil, nil } +func opRand(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + evm := interpreter.evm + + nonce := evm.StateDB.GetNonce(contract.Caller()) + binaryNonce := make([]byte, binary.MaxVarintLen64) + binary.PutUvarint(binaryNonce, nonce) + + binaryGas := make([]byte, binary.MaxVarintLen64) + binary.PutUvarint(binaryGas, contract.Gas) + + hash := crypto.Keccak256( + evm.Randomness, + contract.Caller().Bytes(), + binaryNonce, + binaryGas) + + stack.push(interpreter.intPool.get().SetBytes(hash)) + return nil, nil +} + func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(contract.Address().Big()) return nil, nil diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index da158027a..608e34419 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -301,6 +301,12 @@ func newFrontierInstructionSet() [256]operation { memorySize: memorySha3, valid: true, }, + RAND: { + execute: opRand, + gasCost: constGasFunc(params.RandGas), + validateStack: makeStackFunc(0, 1), + valid: true, + }, ADDRESS: { execute: opAddress, gasCost: constGasFunc(GasQuickStep), diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 4349ffd29..8762d4b43 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -71,6 +71,7 @@ const ( SAR SHA3 = 0x20 + RAND = 0x2f ) // 0x30 range - closure state. @@ -251,6 +252,7 @@ var opCodeToString = map[OpCode]string{ // 0x20 range - crypto. SHA3: "SHA3", + RAND: "RAND", // 0x30 range - closure state. ADDRESS: "ADDRESS", @@ -420,6 +422,7 @@ var stringToOp = map[string]OpCode{ "ADDMOD": ADDMOD, "MULMOD": MULMOD, "SHA3": SHA3, + "RAND": RAND, "ADDRESS": ADDRESS, "BALANCE": BALANCE, "ORIGIN": ORIGIN, -- cgit v1.2.3