diff options
author | Wei-Ning Huang <w@cobinhood.com> | 2018-10-18 13:12:16 +0800 |
---|---|---|
committer | Wei-Ning Huang <w@dexon.org> | 2019-03-12 12:19:09 +0800 |
commit | 6795fe7ac5b8dedf3d1ce7fdfb7f5113d60f0421 (patch) | |
tree | 25ec550517d0e65e67596238ba9dfe84266642e7 | |
parent | cf3c29bd89848492440a0010f6aa6ee79f3f149c (diff) | |
download | dexon-6795fe7ac5b8dedf3d1ce7fdfb7f5113d60f0421.tar.gz dexon-6795fe7ac5b8dedf3d1ce7fdfb7f5113d60f0421.tar.zst dexon-6795fe7ac5b8dedf3d1ce7fdfb7f5113d60f0421.zip |
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.
-rw-r--r-- | core/evm.go | 1 | ||||
-rw-r--r-- | core/types/block.go | 1 | ||||
-rw-r--r-- | core/types/gen_header_json.go | 7 | ||||
-rw-r--r-- | core/types/gen_log_json.go | 2 | ||||
-rw-r--r-- | core/types/gen_tx_json.go | 2 | ||||
-rw-r--r-- | core/vm/evm.go | 1 | ||||
-rw-r--r-- | core/vm/instructions.go | 22 | ||||
-rw-r--r-- | core/vm/jump_table.go | 6 | ||||
-rw-r--r-- | core/vm/opcodes.go | 3 | ||||
-rw-r--r-- | params/protocol_params.go | 1 |
10 files changed, 46 insertions, 0 deletions
diff --git a/core/evm.go b/core/evm.go index b958a0b13..1fb47199b 100644 --- a/core/evm.go +++ b/core/evm.go @@ -52,6 +52,7 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author Coinbase: beneficiary, BlockNumber: new(big.Int).Set(header.Number), Time: new(big.Int).Set(header.Time), + Randomness: header.Randomness, Difficulty: new(big.Int).Set(header.Difficulty), GasLimit: header.GasLimit, GasPrice: new(big.Int).Set(msg.GasPrice()), diff --git a/core/types/block.go b/core/types/block.go index 3d0997f5e..9532beb2d 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -83,6 +83,7 @@ type Header struct { Extra []byte `json:"extraData" gencodec:"required"` MixDigest common.Hash `json:"mixHash"` Nonce BlockNonce `json:"nonce"` + Randomness []byte `json:"randomness" gencodec:"required"` } // field type overrides for gencodec diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index ef2249311..4f844b406 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -31,6 +31,7 @@ func (h Header) MarshalJSON() ([]byte, error) { Extra hexutil.Bytes `json:"extraData" gencodec:"required"` MixDigest common.Hash `json:"mixHash"` Nonce BlockNonce `json:"nonce"` + Randomness []byte `json:"randomness" gencodec:"required"` Hash common.Hash `json:"hash"` } var enc Header @@ -49,6 +50,7 @@ func (h Header) MarshalJSON() ([]byte, error) { enc.Extra = h.Extra enc.MixDigest = h.MixDigest enc.Nonce = h.Nonce + enc.Randomness = h.Randomness enc.Hash = h.Hash() return json.Marshal(&enc) } @@ -71,6 +73,7 @@ func (h *Header) UnmarshalJSON(input []byte) error { Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` MixDigest *common.Hash `json:"mixHash"` Nonce *BlockNonce `json:"nonce"` + Randomness []byte `json:"randomness" gencodec:"required"` } var dec Header if err := json.Unmarshal(input, &dec); err != nil { @@ -134,5 +137,9 @@ func (h *Header) UnmarshalJSON(input []byte) error { if dec.Nonce != nil { h.Nonce = *dec.Nonce } + if dec.Randomness == nil { + return errors.New("missing required field 'randomness' for Header") + } + h.Randomness = dec.Randomness return nil } diff --git a/core/types/gen_log_json.go b/core/types/gen_log_json.go index 4d24b92fd..e301a69c8 100644 --- a/core/types/gen_log_json.go +++ b/core/types/gen_log_json.go @@ -12,6 +12,7 @@ import ( var _ = (*logMarshaling)(nil) +// MarshalJSON marshals as JSON. func (l Log) MarshalJSON() ([]byte, error) { type Log struct { Address common.Address `json:"address" gencodec:"required"` @@ -37,6 +38,7 @@ func (l Log) MarshalJSON() ([]byte, error) { return json.Marshal(&enc) } +// UnmarshalJSON unmarshals from JSON. func (l *Log) UnmarshalJSON(input []byte) error { type Log struct { Address *common.Address `json:"address" gencodec:"required"` diff --git a/core/types/gen_tx_json.go b/core/types/gen_tx_json.go index b1415094b..2f216dfb9 100644 --- a/core/types/gen_tx_json.go +++ b/core/types/gen_tx_json.go @@ -13,6 +13,7 @@ import ( var _ = (*txdataMarshaling)(nil) +// MarshalJSON marshals as JSON. func (t txdata) MarshalJSON() ([]byte, error) { type txdata struct { AccountNonce hexutil.Uint64 `json:"nonce" gencodec:"required"` @@ -40,6 +41,7 @@ func (t txdata) MarshalJSON() ([]byte, error) { return json.Marshal(&enc) } +// UnmarshalJSON unmarshals from JSON. func (t *txdata) UnmarshalJSON(input []byte) error { type txdata struct { AccountNonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` 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, diff --git a/params/protocol_params.go b/params/protocol_params.go index c8b6609af..6b1787922 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -37,6 +37,7 @@ const ( Sha3Gas uint64 = 30 // Once per SHA3 operation. Sha3WordGas uint64 = 6 // Once per word of the SHA3 operation's data. + RandGas uint64 = 36 // Once per random seed load. SstoreSetGas uint64 = 20000 // Once per SLOAD operation. SstoreResetGas uint64 = 5000 // Once per SSTORE operation if the zeroness changes from zero. |