aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei-Ning Huang <w@cobinhood.com>2018-10-18 13:12:16 +0800
committerWei-Ning Huang <w@dexon.org>2019-04-09 21:32:50 +0800
commit6137f79f726e8ec6a282ee0ca4ed45c05020ed4c (patch)
tree9a9e5c3cc01e0a7c1898799562e13fabeaf608d5
parent1fa4415d48e4ed7ee0f75ed21e62847ea68d3a0f (diff)
downloaddexon-6137f79f726e8ec6a282ee0ca4ed45c05020ed4c.tar
dexon-6137f79f726e8ec6a282ee0ca4ed45c05020ed4c.tar.gz
dexon-6137f79f726e8ec6a282ee0ca4ed45c05020ed4c.tar.bz2
dexon-6137f79f726e8ec6a282ee0ca4ed45c05020ed4c.tar.lz
dexon-6137f79f726e8ec6a282ee0ca4ed45c05020ed4c.tar.xz
dexon-6137f79f726e8ec6a282ee0ca4ed45c05020ed4c.tar.zst
dexon-6137f79f726e8ec6a282ee0ca4ed45c05020ed4c.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.go1
-rw-r--r--core/types/block.go1
-rw-r--r--core/types/gen_header_json.go7
-rw-r--r--core/types/gen_log_json.go2
-rw-r--r--core/types/gen_tx_json.go2
-rw-r--r--core/vm/evm.go1
-rw-r--r--core/vm/instructions.go22
-rw-r--r--core/vm/jump_table.go6
-rw-r--r--core/vm/opcodes.go3
-rw-r--r--params/protocol_params.go1
10 files changed, 46 insertions, 0 deletions
diff --git a/core/evm.go b/core/evm.go
index bf723cf9e..2d58e33f8 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).SetUint64(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 b568c2b37..ef2cb2c56 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 4c028337f..d06b07769 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.