Skip to content

Commit

Permalink
Recovering Randomness (ethereum#325)
Browse files Browse the repository at this point in the history
* changed randomness to hash(sign(string) + prevBlockHash)

* lint

* minor fix

* recover last block hash by iterating

* changed log msg

* lint
  • Loading branch information
nicholasguo authored Aug 5, 2019
1 parent b8183c6 commit 595e245
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 24 deletions.
43 changes: 21 additions & 22 deletions contract_comm/random/random.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package random

import (
"crypto/rand"
"strings"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/contract_comm"
"github.com/ethereum/go-ethereum/contract_comm/errors"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
Expand Down Expand Up @@ -62,7 +63,6 @@ const (
"type": "function"
}
]`

computeCommitmentAbi = `[
{
"constant": true,
Expand Down Expand Up @@ -92,7 +92,7 @@ var (
commitmentsFuncABI, _ = abi.JSON(strings.NewReader(commitmentsAbi))
computeCommitmentFuncABI, _ = abi.JSON(strings.NewReader(computeCommitmentAbi))
zeroValue = common.Big0
dbRandomnessPrefix = []byte("commitment-to-randomness")
dbRandomnessPrefix = []byte("db-randomness-prefix")
)

func commitmentDbLocation(commitment common.Hash) []byte {
Expand All @@ -118,7 +118,7 @@ func IsRunning() bool {
// looking up our last commitment in the smart contract, and then finding the
// corresponding preimage in a (commitment => randomness) mapping we keep in the
// database.
func GetLastRandomness(coinbase common.Address, db *ethdb.Database, header *types.Header, state vm.StateDB) (common.Hash, error) {
func GetLastRandomness(coinbase common.Address, db *ethdb.Database, header *types.Header, state vm.StateDB, chain consensus.ChainReader, seed []byte) (common.Hash, error) {
lastCommitment := common.Hash{}
_, err := contract_comm.MakeStaticCall(params.RandomRegistryId, commitmentsFuncABI, "commitments", []interface{}{coinbase}, &lastCommitment, gasAmount, header, state)
if err != nil {
Expand All @@ -131,33 +131,32 @@ func GetLastRandomness(coinbase common.Address, db *ethdb.Database, header *type
return common.Hash{}, nil
}

randomness := common.Hash{}
randomnessSlice, err := (*db).Get(commitmentDbLocation(lastCommitment))
parentBlockHashBytes, err := (*db).Get(commitmentDbLocation(lastCommitment))
if err != nil {
log.Error("Failed to get randomness from database", "commitment", lastCommitment.Hex(), "err", err)
} else {
randomness = common.BytesToHash(randomnessSlice)
log.Error("Failed to get last block proposed from database", "commitment", lastCommitment.Hex(), "err", err)
parentBlockHash := header.ParentHash
for {
blockHeader := chain.GetHeaderByHash(parentBlockHash)
parentBlockHash = blockHeader.ParentHash
if blockHeader.Coinbase == coinbase {
break
}
}
parentBlockHashBytes = parentBlockHash.Bytes()
}
return randomness, err
return crypto.Keccak256Hash(append(seed, parentBlockHashBytes...)), nil
}

// GenerateNewRandomnessAndCommitment generates a new random number and a corresponding commitment.
// The random number is stored in the database, keyed by the corresponding commitment.
func GenerateNewRandomnessAndCommitment(header *types.Header, state vm.StateDB, db *ethdb.Database) (common.Hash, error) {
func GenerateNewRandomnessAndCommitment(header *types.Header, state vm.StateDB, db *ethdb.Database, seed []byte) (common.Hash, error) {
commitment := common.Hash{}

randomBytes := [32]byte{}
_, err := rand.Read(randomBytes[0:32])
if err != nil {
log.Error("Failed to generate randomness", "err", err)
return commitment, err
}
randomness := common.BytesToHash(randomBytes[:])
randomness := crypto.Keccak256Hash(append(seed, header.ParentHash.Bytes()...))
// TODO(asa): Make an issue to not have to do this via StaticCall
_, err = contract_comm.MakeStaticCall(params.RandomRegistryId, computeCommitmentFuncABI, "computeCommitment", []interface{}{randomness}, &commitment, gasAmount, header, state)
err = (*db).Put(commitmentDbLocation(commitment), randomness[:])
_, err := contract_comm.MakeStaticCall(params.RandomRegistryId, computeCommitmentFuncABI, "computeCommitment", []interface{}{randomness}, &commitment, gasAmount, header, state)
err = (*db).Put(commitmentDbLocation(commitment), header.ParentHash.Bytes())
if err != nil {
log.Error("Failed to save randomness to the database", "err", err)
log.Error("Failed to save last block parentHash to the database", "err", err)
}
return commitment, err
}
Expand Down
22 changes: 20 additions & 2 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

mapset "github.com/deckarep/golang-set"
"github.com/ethereum/go-ethereum/abe"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc"
Expand Down Expand Up @@ -81,6 +82,11 @@ const (
staleThreshold = 7
)

var (
randomSeedString = []byte("Randomness seed string")
randomSeed []byte
)

// environment is the worker's current environment and holds all of the current state information.
type environment struct {
signer types.Signer
Expand Down Expand Up @@ -984,13 +990,25 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64)

// Play our part in generating the random beacon.
if w.isRunning() && random.IsRunning() {
lastRandomness, err := random.GetLastRandomness(w.coinbase, w.db, w.current.header, w.current.state)
if randomSeed == nil {
account := accounts.Account{Address: w.coinbase}
wallet, err := w.eth.AccountManager().Find(account)
if err == nil {
randomSeed, err = wallet.SignHash(account, common.BytesToHash(randomSeedString).Bytes())
}
if err != nil {
log.Error("Unable to create random seed", "err", err)
return
}
}

lastRandomness, err := random.GetLastRandomness(w.coinbase, w.db, w.current.header, w.current.state, w.chain, randomSeed)
if err != nil {
log.Error("Failed to get last randomness", "err", err)
return
}

commitment, err := random.GenerateNewRandomnessAndCommitment(w.current.header, w.current.state, w.db)
commitment, err := random.GenerateNewRandomnessAndCommitment(w.current.header, w.current.state, w.db, randomSeed)
if err != nil {
log.Error("Failed to generate randomness commitment", "err", err)
return
Expand Down

0 comments on commit 595e245

Please sign in to comment.