add history vrf reading capability on vrf precompile (#3850)

* precompile for history vrfs

* remove prints
pull/3854/head
Rongjian Lan 3 years ago committed by GitHub
parent 2393c9cced
commit 305ef3514a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 41
      core/evm.go
  2. 25
      core/vm/evm.go
  3. 1
      core/vm/runtime/env.go
  4. 23
      internal/params/config.go

@ -70,6 +70,7 @@ func NewEVMContext(msg Message, header *block.Header, chain ChainContext, author
Transfer: Transfer, Transfer: Transfer,
IsValidator: IsValidator, IsValidator: IsValidator,
GetHash: GetHashFn(header, chain), GetHash: GetHashFn(header, chain),
GetVRF: GetVRFFn(header, chain),
Origin: msg.From(), Origin: msg.From(),
Coinbase: beneficiary, Coinbase: beneficiary,
BlockNumber: header.Number(), BlockNumber: header.Number(),
@ -107,6 +108,46 @@ func GetHashFn(ref *block.Header, chain ChainContext) func(n uint64) common.Hash
} }
} }
// GetVRFFn returns a GetVRFFn which retrieves header vrf by number
func GetVRFFn(ref *block.Header, chain ChainContext) func(n uint64) common.Hash {
var cache map[uint64]common.Hash
return func(n uint64) common.Hash {
// If there's no hash cache yet, make one
if cache == nil {
curVRF := common.Hash{}
if len(ref.Vrf()) >= 32 {
vrfAndProof := ref.Vrf()
copy(curVRF[:], vrfAndProof[:32])
}
cache = map[uint64]common.Hash{
ref.Number().Uint64(): curVRF,
}
}
// Try to fulfill the request from the cache
if hash, ok := cache[n]; ok {
return hash
}
// Not cached, iterate the blocks and cache the hashes
for header := chain.GetHeader(ref.ParentHash(), ref.Number().Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash(), header.Number().Uint64()-1) {
curVRF := common.Hash{}
if len(header.Vrf()) >= 32 {
vrfAndProof := header.Vrf()
copy(curVRF[:], vrfAndProof[:32])
}
cache[header.Number().Uint64()] = curVRF
if n == header.Number().Uint64() {
return curVRF
}
}
return common.Hash{}
}
}
// CanTransfer checks whether there are enough funds in the address' account to make a transfer. // CanTransfer checks whether there are enough funds in the address' account to make a transfer.
// This does not take the necessary gas in to account to make the transfer valid. // This does not take the necessary gas in to account to make the transfer valid.
func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool { func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool {

@ -42,6 +42,9 @@ type (
// GetHashFunc returns the nth block hash in the blockchain // GetHashFunc returns the nth block hash in the blockchain
// and is used by the BLOCKHASH EVM op code. // and is used by the BLOCKHASH EVM op code.
GetHashFunc func(uint64) common.Hash GetHashFunc func(uint64) common.Hash
// GetVRFFunc returns the nth block vrf in the blockchain
// and is used by the precompile VRF contract.
GetVRFFunc func(uint64) common.Hash
) )
// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
@ -59,8 +62,24 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err
} }
if p := precompiles[*contract.CodeAddr]; p != nil { if p := precompiles[*contract.CodeAddr]; p != nil {
if _, ok := p.(*vrf); ok { if _, ok := p.(*vrf); ok {
// Override the input with vrf data of the current block so it can be returned to the contract program. if evm.chainRules.IsPrevVRF {
input = evm.Context.VRF.Bytes() requestedBlockNum := big.NewInt(0).SetBytes(input[0:32])
minBlockNum := big.NewInt(0).Sub(evm.BlockNumber, common.Big257)
if requestedBlockNum.Cmp(evm.BlockNumber) == 0 {
input = evm.Context.VRF.Bytes()
} else if requestedBlockNum.Cmp(minBlockNum) > 0 && requestedBlockNum.Cmp(evm.BlockNumber) < 0 {
// requested block number is in range
input = evm.GetVRF(requestedBlockNum.Uint64()).Bytes()
} else {
// else default to the current block's VRF
input = evm.Context.VRF.Bytes()
}
} else {
// Override the input with vrf data of the requested block so it can be returned to the contract program.
input = evm.Context.VRF.Bytes()
}
} }
return RunPrecompiledContract(p, input, contract) return RunPrecompiledContract(p, input, contract)
} }
@ -92,6 +111,8 @@ type Context struct {
Transfer TransferFunc Transfer TransferFunc
// GetHash returns the hash corresponding to n // GetHash returns the hash corresponding to n
GetHash GetHashFunc GetHash GetHashFunc
// GetVRF returns the VRF corresponding to n
GetVRF GetVRFFunc
// IsValidator determines whether the address corresponds to a validator or a smart contract // IsValidator determines whether the address corresponds to a validator or a smart contract
// true: is a validator address; false: is smart contract address // true: is a validator address; false: is smart contract address

@ -29,6 +29,7 @@ func NewEnv(cfg *Config) *vm.EVM {
Transfer: core.Transfer, Transfer: core.Transfer,
IsValidator: core.IsValidator, IsValidator: core.IsValidator,
GetHash: func(uint64) common.Hash { return common.Hash{} }, GetHash: func(uint64) common.Hash { return common.Hash{} },
GetVRF: func(uint64) common.Hash { return common.Hash{} },
Origin: cfg.Origin, Origin: cfg.Origin,
Coinbase: cfg.Coinbase, Coinbase: cfg.Coinbase,

@ -52,6 +52,7 @@ var (
RedelegationEpoch: big.NewInt(290), RedelegationEpoch: big.NewInt(290),
NoEarlyUnlockEpoch: big.NewInt(530), // Around Monday Apr 12th 2021, 22:30 UTC NoEarlyUnlockEpoch: big.NewInt(530), // Around Monday Apr 12th 2021, 22:30 UTC
VRFEpoch: big.NewInt(631), // Around Wed July 7th 2021 VRFEpoch: big.NewInt(631), // Around Wed July 7th 2021
PrevVRFEpoch: EpochTBD,
MinDelegation100Epoch: big.NewInt(631), // Around Wed July 7th 2021 MinDelegation100Epoch: big.NewInt(631), // Around Wed July 7th 2021
MinCommissionRateEpoch: big.NewInt(631), // Around Wed July 7th 2021 MinCommissionRateEpoch: big.NewInt(631), // Around Wed July 7th 2021
MinCommissionPromoPeriod: big.NewInt(100), MinCommissionPromoPeriod: big.NewInt(100),
@ -80,6 +81,7 @@ var (
RedelegationEpoch: big.NewInt(36500), RedelegationEpoch: big.NewInt(36500),
NoEarlyUnlockEpoch: big.NewInt(73580), NoEarlyUnlockEpoch: big.NewInt(73580),
VRFEpoch: big.NewInt(73880), VRFEpoch: big.NewInt(73880),
PrevVRFEpoch: EpochTBD,
MinDelegation100Epoch: big.NewInt(73880), MinDelegation100Epoch: big.NewInt(73880),
MinCommissionRateEpoch: big.NewInt(73880), MinCommissionRateEpoch: big.NewInt(73880),
MinCommissionPromoPeriod: big.NewInt(10), MinCommissionPromoPeriod: big.NewInt(10),
@ -109,6 +111,7 @@ var (
RedelegationEpoch: big.NewInt(0), RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0), NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0), VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0), MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0), MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10), MinCommissionPromoPeriod: big.NewInt(10),
@ -138,6 +141,7 @@ var (
RedelegationEpoch: big.NewInt(0), RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0), NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0), VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0), MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0), MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10), MinCommissionPromoPeriod: big.NewInt(10),
@ -167,6 +171,7 @@ var (
RedelegationEpoch: big.NewInt(0), RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0), NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0), VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0), MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0), MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10), MinCommissionPromoPeriod: big.NewInt(10),
@ -195,6 +200,7 @@ var (
RedelegationEpoch: big.NewInt(0), RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0), NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0), VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0), MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0), MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10), MinCommissionPromoPeriod: big.NewInt(10),
@ -225,6 +231,7 @@ var (
big.NewInt(0), // RedelegationEpoch big.NewInt(0), // RedelegationEpoch
big.NewInt(0), // NoEarlyUnlockEpoch big.NewInt(0), // NoEarlyUnlockEpoch
big.NewInt(0), // VRFEpoch big.NewInt(0), // VRFEpoch
big.NewInt(0), // PrevVRFEpoch
big.NewInt(0), // MinDelegation100Epoch big.NewInt(0), // MinDelegation100Epoch
big.NewInt(0), // MinCommissionRateEpoch big.NewInt(0), // MinCommissionRateEpoch
big.NewInt(10), // MinCommissionPromoPeriod big.NewInt(10), // MinCommissionPromoPeriod
@ -255,6 +262,7 @@ var (
big.NewInt(0), // RedelegationEpoch big.NewInt(0), // RedelegationEpoch
big.NewInt(0), // NoEarlyUnlockEpoch big.NewInt(0), // NoEarlyUnlockEpoch
big.NewInt(0), // VRFEpoch big.NewInt(0), // VRFEpoch
big.NewInt(0), // PrevVRFEpoch
big.NewInt(0), // MinDelegation100Epoch big.NewInt(0), // MinDelegation100Epoch
big.NewInt(0), // MinCommissionRateEpoch big.NewInt(0), // MinCommissionRateEpoch
big.NewInt(10), // MinCommissionPromoPeriod big.NewInt(10), // MinCommissionPromoPeriod
@ -342,6 +350,9 @@ type ChainConfig struct {
// VRFEpoch is the epoch when VRF randomness is enabled // VRFEpoch is the epoch when VRF randomness is enabled
VRFEpoch *big.Int `json:"vrf-epoch,omitempty"` VRFEpoch *big.Int `json:"vrf-epoch,omitempty"`
// PrevVRFEpoch is the epoch when previous VRF randomness can be fetched
PrevVRFEpoch *big.Int `json:"prev-vrf-epoch,omitempty"`
// MinDelegation100Epoch is the epoch when min delegation is reduced from 1000 ONE to 100 ONE // MinDelegation100Epoch is the epoch when min delegation is reduced from 1000 ONE to 100 ONE
MinDelegation100Epoch *big.Int `json:"min-delegation-100-epoch,omitempty"` MinDelegation100Epoch *big.Int `json:"min-delegation-100-epoch,omitempty"`
@ -450,6 +461,11 @@ func (c *ChainConfig) IsVRF(epoch *big.Int) bool {
return isForked(c.VRFEpoch, epoch) return isForked(c.VRFEpoch, epoch)
} }
// IsPrevVRF determines whether it is the epoch to enable previous vrf
func (c *ChainConfig) IsPrevVRF(epoch *big.Int) bool {
return isForked(c.PrevVRFEpoch, epoch)
}
// IsMinDelegation100 determines whether it is the epoch to reduce min delegation to 100 // IsMinDelegation100 determines whether it is the epoch to reduce min delegation to 100
func (c *ChainConfig) IsMinDelegation100(epoch *big.Int) bool { func (c *ChainConfig) IsMinDelegation100(epoch *big.Int) bool {
return isForked(c.MinDelegation100Epoch, epoch) return isForked(c.MinDelegation100Epoch, epoch)
@ -543,9 +559,9 @@ func isForked(s, epoch *big.Int) bool {
// Rules is a one time interface meaning that it shouldn't be used in between transition // Rules is a one time interface meaning that it shouldn't be used in between transition
// phases. // phases.
type Rules struct { type Rules struct {
ChainID *big.Int ChainID *big.Int
EthChainID *big.Int EthChainID *big.Int
IsCrossLink, IsEIP155, IsS3, IsReceiptLog, IsIstanbul, IsVRF bool IsCrossLink, IsEIP155, IsS3, IsReceiptLog, IsIstanbul, IsVRF, IsPrevVRF bool
} }
// Rules ensures c's ChainID is not nil. // Rules ensures c's ChainID is not nil.
@ -567,5 +583,6 @@ func (c *ChainConfig) Rules(epoch *big.Int) Rules {
IsReceiptLog: c.IsReceiptLog(epoch), IsReceiptLog: c.IsReceiptLog(epoch),
IsIstanbul: c.IsIstanbul(epoch), IsIstanbul: c.IsIstanbul(epoch),
IsVRF: c.IsVRF(epoch), IsVRF: c.IsVRF(epoch),
IsPrevVRF: c.IsPrevVRF(epoch),
} }
} }

Loading…
Cancel
Save