diff options
author | Jhih-Ming Huang <jm@byzantine-lab.io> | 2019-06-19 17:49:27 +0800 |
---|---|---|
committer | Wei-Ning Huang <w@byzantine-lab.io> | 2019-09-17 16:57:30 +0800 |
commit | c3c6574c9053a361bfe4f77bf4e1ae99d19f60dc (patch) | |
tree | 1a2b1db4b51bb084b5340d9875b968aaee87976c | |
parent | aa9c5b22941aadfefcde64d2570d6c6863bc2ebe (diff) | |
download | go-tangerine-c3c6574c9053a361bfe4f77bf4e1ae99d19f60dc.tar.gz go-tangerine-c3c6574c9053a361bfe4f77bf4e1ae99d19f60dc.tar.zst go-tangerine-c3c6574c9053a361bfe4f77bf4e1ae99d19f60dc.zip |
core: vm: remove opRand and use oracle contract to get random number
-rw-r--r-- | core/vm/evm.go | 2 | ||||
-rw-r--r-- | core/vm/instructions.go | 24 | ||||
-rw-r--r-- | core/vm/jump_table.go | 6 | ||||
-rw-r--r-- | core/vm/opcodes.go | 3 | ||||
-rw-r--r-- | core/vm/oracle.go | 4 | ||||
-rw-r--r-- | core/vm/oracle_contracts.go | 32 | ||||
-rw-r--r-- | core/vm/oracle_contracts_test.go | 48 | ||||
-rw-r--r-- | params/protocol_params.go | 2 |
8 files changed, 86 insertions, 35 deletions
diff --git a/core/vm/evm.go b/core/vm/evm.go index 84b98d7c2..ea370f11f 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -103,7 +103,7 @@ type Context struct { Difficulty *big.Int // Provides information for DIFFICULTY Round *big.Int // Current round number. - RandCallIndex uint64 // Number of times opRand is called + RandCallIndex uint64 // Number of times RandomContract is called } // EVM is the Ethereum Virtual Machine base object and provides diff --git a/core/vm/instructions.go b/core/vm/instructions.go index b096bfdd4..587acf002 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -17,7 +17,6 @@ package vm import ( - "encoding/binary" "errors" "fmt" "math/big" @@ -25,7 +24,6 @@ import ( "github.com/tangerine-network/go-tangerine/common" "github.com/tangerine-network/go-tangerine/common/math" "github.com/tangerine-network/go-tangerine/core/types" - "github.com/tangerine-network/go-tangerine/crypto" "github.com/tangerine-network/go-tangerine/params" "golang.org/x/crypto/sha3" ) @@ -410,28 +408,6 @@ 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(evm.Origin) - binaryOriginNonce := make([]byte, binary.MaxVarintLen64) - binary.PutUvarint(binaryOriginNonce, nonce) - - binaryUsedIndex := make([]byte, binary.MaxVarintLen64) - binary.PutUvarint(binaryUsedIndex, evm.RandCallIndex) - - evm.RandCallIndex += 1 - - hash := crypto.Keccak256( - evm.Randomness, - evm.Origin.Bytes(), - binaryOriginNonce, - binaryUsedIndex) - - 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 c1b57ea89..ba11b57f3 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -301,12 +301,6 @@ 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 8762d4b43..4349ffd29 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -71,7 +71,6 @@ const ( SAR SHA3 = 0x20 - RAND = 0x2f ) // 0x30 range - closure state. @@ -252,7 +251,6 @@ var opCodeToString = map[OpCode]string{ // 0x20 range - crypto. SHA3: "SHA3", - RAND: "RAND", // 0x30 range - closure state. ADDRESS: "ADDRESS", @@ -422,7 +420,6 @@ var stringToOp = map[string]OpCode{ "ADDMOD": ADDMOD, "MULMOD": MULMOD, "SHA3": SHA3, - "RAND": RAND, "ADDRESS": ADDRESS, "BALANCE": BALANCE, "ORIGIN": ORIGIN, diff --git a/core/vm/oracle.go b/core/vm/oracle.go index b2dac4521..2e27983b5 100644 --- a/core/vm/oracle.go +++ b/core/vm/oracle.go @@ -25,6 +25,7 @@ import ( ) var GovernanceContractAddress = common.HexToAddress("63751838d6485578b23e8b051d40861ecc416794") +var RandomContractAddress = common.HexToAddress("03C90084388Be8E088425DA9835F7f43F8a319c7") var GovernanceABI *OracleContractABI @@ -44,6 +45,9 @@ var OracleContracts = map[common.Address]func() OracleContract{ coreDKGUtils: &defaultCoreDKGUtils{}, } }, + RandomContractAddress: func() OracleContract { + return &RandomContract{} + }, } // Run oracle contract. diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go index 484ed82b8..7e245e6bd 100644 --- a/core/vm/oracle_contracts.go +++ b/core/vm/oracle_contracts.go @@ -19,6 +19,7 @@ package vm import ( "bytes" + "encoding/binary" "errors" "fmt" "math" @@ -2952,3 +2953,34 @@ func PackResetDKG(newSignedCRS []byte) ([]byte, error) { data := append(method.Id(), res...) return data, nil } + +// RandomContract provides access to on chain randomness. +type RandomContract struct { + evm *EVM + contract *Contract +} + +func (*RandomContract) Run(evm *EVM, input []byte, + contract *Contract) (ret []byte, err error) { + nonce := evm.StateDB.GetNonce(evm.Origin) + + cost := params.RandGas + if !contract.UseGas(cost) { + return nil, ErrOutOfGas + } + + binaryOriginNonce := make([]byte, binary.MaxVarintLen64) + binary.PutUvarint(binaryOriginNonce, nonce) + + binaryUsedIndex := make([]byte, binary.MaxVarintLen64) + binary.PutUvarint(binaryUsedIndex, evm.RandCallIndex) + + evm.RandCallIndex += 1 + + ret = crypto.Keccak256( + evm.Randomness, + evm.Origin.Bytes(), + binaryOriginNonce, + binaryUsedIndex) + return +} diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go index 33fdba886..ddd75810e 100644 --- a/core/vm/oracle_contracts_test.go +++ b/core/vm/oracle_contracts_test.go @@ -1247,3 +1247,51 @@ func (g *OracleContractsTestSuite) TestResetDKG() { func TestOracleContracts(t *testing.T) { suite.Run(t, new(OracleContractsTestSuite)) } + +type RandomContractTestSuite struct { + suite.Suite + + context Context + stateDB *state.StateDB + config *params.DexconConfig +} + +func (r *RandomContractTestSuite) SetupTest() { + memDB := ethdb.NewMemDatabase() + stateDB, err := state.New(common.Hash{}, state.NewDatabase(memDB)) + if err != nil { + panic(err) + } + r.stateDB = stateDB + r.context = Context{ + CanTransfer: func(db StateDB, addr common.Address, amount *big.Int) bool { + return db.GetBalance(addr).Cmp(amount) >= 0 + }, + Transfer: func(db StateDB, sender common.Address, recipient common.Address, amount *big.Int) { + db.SubBalance(sender, amount) + db.AddBalance(recipient, amount) + }, + } + r.config = params.TestnetChainConfig.Dexcon +} + +func (r *RandomContractTestSuite) TestRun() { + evm := NewEVM(r.context, r.stateDB, params.TestChainConfig, + Config{IsBlockProposer: true}) + contractAddr := RandomContractAddress + caller := r.config.Owner + randCallIndex := evm.RandCallIndex + + ret, _, err := evm.Call(AccountRef(caller), contractAddr, nil, 64, big.NewInt(0)) + r.Require().Nil(err) + r.Require().Equal(randCallIndex+1, evm.RandCallIndex) + r.Require().NotNil(ret) + + _, _, err = evm.Call(AccountRef(caller), contractAddr, nil, 63, big.NewInt(0)) + r.Require().Equal(err, ErrOutOfGas) + r.Require().Equal(randCallIndex+1, evm.RandCallIndex) +} + +func TestRandomContract(t *testing.T) { + suite.Run(t, new(RandomContractTestSuite)) +} diff --git a/params/protocol_params.go b/params/protocol_params.go index 6b1787922..84574e19f 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -37,7 +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. + RandGas uint64 = 64 // 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. |