Merge pull request #1257 from harmony-one/vdf_3

DRG generation (VRF/VDF integration)
pull/1274/head
coolcottontail 5 years ago committed by GitHub
commit 2c3ae299f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 22
      consensus/consensus.go
  2. 17
      consensus/consensus_service.go
  3. 249
      consensus/consensus_v2.go
  4. 145
      core/blockchain.go
  5. 23
      core/rawdb/accessors_chain.go
  6. 14
      core/rawdb/schema.go
  7. 34
      core/types/block.go
  8. 1
      go.mod
  9. 4
      internal/configs/sharding/fixedschedule.go
  10. 6
      internal/configs/sharding/localnet.go
  11. 6
      internal/configs/sharding/mainnet.go
  12. 3
      internal/configs/sharding/shardingconfig.go
  13. 6
      internal/configs/sharding/testnet.go

@ -7,11 +7,10 @@ import (
"sync"
"time"
"github.com/harmony-one/harmony/core"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/common/denominations"
consensus_engine "github.com/harmony-one/harmony/consensus/engine"
@ -27,6 +26,11 @@ import (
"github.com/harmony-one/harmony/p2p"
)
const (
vdFAndProofSize = 516 // size of VDF and Proof
vdfAndSeedSize = 548 // size of VDF/Proof and Seed
)
// BlockReward is the block reward, to be split evenly among block signers.
var BlockReward = new(big.Int).Mul(big.NewInt(24), big.NewInt(denominations.One))
@ -134,9 +138,9 @@ type Consensus struct {
// Channel for DRG protocol to send pRnd (preimage of randomness resulting from combined vrf randomnesses) to consensus. The first 32 bytes are randomness, the rest is for bitmap.
PRndChannel chan []byte
// Channel for DRG protocol to send the final randomness to consensus. The first 32 bytes are the randomness and the last 32 bytes are the hash of the block where the corresponding pRnd was generated
RndChannel chan [64]byte
pendingRnds [][64]byte // A list of pending randomness
// Channel for DRG protocol to send VDF. The first 516 bytes are the VDF/Proof and the last 32 bytes are the seed for deriving VDF
RndChannel chan [vdfAndSeedSize]byte
pendingRnds [][vdfAndSeedSize]byte // A list of pending randomness
uniqueIDInstance *utils.UniqueValidatorID
@ -211,6 +215,11 @@ func (consensus *Consensus) PreviousQuorum() int {
return consensus.numPrevPubKeys*2/3 + 1
}
// VdfSeedSize returns the number of VRFs for VDF computation
func (consensus *Consensus) VdfSeedSize() int {
return len(consensus.PublicKeys) * 2 / 3
}
// RewardThreshold returns the threshold to stop accepting commit messages
// when leader receives enough signatures for block reward
func (consensus *Consensus) RewardThreshold() int {
@ -273,6 +282,9 @@ func New(host p2p.Host, ShardID uint32, leader p2p.Peer, blsPriKey *bls.SecretKe
consensus.ReadySignal = make(chan struct{})
// channel for receiving newly generated VDF
consensus.RndChannel = make(chan [vdfAndSeedSize]byte)
consensus.uniqueIDInstance = utils.GetUniqueValidatorIDInstance()
memprofiling.GetMemProfiling().Add("consensus.pbftLog", consensus.PbftLog)

@ -39,20 +39,21 @@ func (consensus *Consensus) WaitForNewRandomness() {
}
// GetNextRnd returns the oldest available randomness along with the hash of the block there randomness preimage is committed.
func (consensus *Consensus) GetNextRnd() ([32]byte, [32]byte, error) {
func (consensus *Consensus) GetNextRnd() ([vdFAndProofSize]byte, [32]byte, error) {
if len(consensus.pendingRnds) == 0 {
return [32]byte{}, [32]byte{}, errors.New("No available randomness")
return [vdFAndProofSize]byte{}, [32]byte{}, errors.New("No available randomness")
}
vdfOutput := consensus.pendingRnds[0]
vdfBytes := [vdFAndProofSize]byte{}
seed := [32]byte{}
copy(vdfBytes[:], vdfOutput[:vdFAndProofSize])
copy(seed[:], vdfOutput[vdFAndProofSize:])
//pop the first vdfOutput from the list
consensus.pendingRnds = consensus.pendingRnds[1:]
rnd := [32]byte{}
blockHash := [32]byte{}
copy(rnd[:], vdfOutput[:32])
copy(blockHash[:], vdfOutput[32:])
return rnd, blockHash, nil
return vdfBytes, seed, nil
}
// SealHash returns the hash of a block prior to it being sealed.
@ -489,7 +490,7 @@ func (consensus *Consensus) RegisterPRndChannel(pRndChannel chan []byte) {
}
// RegisterRndChannel registers the channel for receiving final randomness from DRG protocol
func (consensus *Consensus) RegisterRndChannel(rndChannel chan [64]byte) {
func (consensus *Consensus) RegisterRndChannel(rndChannel chan [548]byte) {
consensus.RndChannel = rndChannel
}

@ -15,10 +15,12 @@ import (
msg_pb "github.com/harmony-one/harmony/api/proto/message"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
vrf_bls "github.com/harmony-one/harmony/crypto/vrf/bls"
"github.com/harmony-one/harmony/internal/ctxerror"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/vdf/src/vdf_go"
)
// handleMessageUpdate will update the consensus state according to received message
@ -206,6 +208,23 @@ func (consensus *Consensus) onAnnounce(msg *msg_pb.Message) {
Msg("[OnAnnounce] Block content is not verified successfully")
return
}
//VRF/VDF is only generated in the beach chain
if consensus.ShardID == 0 {
//validate the VRF with proof if a non zero VRF is found in header
if len(headerObj.Vrf) > 0 {
if !consensus.ValidateVrfAndProof(headerObj) {
return
}
}
//validate the VDF with proof if a non zero VDF is found in header
if len(headerObj.Vdf) > 0 {
if !consensus.ValidateVdfAndProof(headerObj) {
return
}
}
}
}
logMsgs := consensus.PbftLog.GetMessagesByTypeSeqView(msg_pb.MessageType_ANNOUNCE, recvMsg.BlockNum, recvMsg.ViewID)
@ -1047,6 +1066,8 @@ func (consensus *Consensus) Start(blockChannel chan *types.Block, stopChan chan
Uint64("viewID", consensus.viewID).
Uint64("block", consensus.blockNum).
Msg("[ConsensusMainLoop] Start bootstrap timeout (only once)")
vdfInProgress := false
for {
select {
case <-ticker.C:
@ -1081,33 +1102,79 @@ func (consensus *Consensus) Start(blockChannel chan *types.Block, stopChan chan
consensus.getLogger().Info().
Uint64("MsgBlockNum", newBlock.NumberU64()).
Msg("[ConsensusMainLoop] Received Proposed New Block!")
//VRF/VDF is only generated in the beacon chain
if consensus.ShardID == 0 {
// TODO ek/rj - re-enable this after fixing DRand
//if core.IsEpochBlock(newBlock) { // Only beacon chain do randomness generation
// // Receive pRnd from DRG protocol
// consensus.getLogger().Debug("[DRG] Waiting for pRnd")
// pRndAndBitmap := <-consensus.PRndChannel
// consensus.getLogger().Debug("[DRG] Got pRnd", "pRnd", pRndAndBitmap)
// pRnd := [32]byte{}
// copy(pRnd[:], pRndAndBitmap[:32])
// bitmap := pRndAndBitmap[32:]
// vrfBitmap, _ := bls_cosi.NewMask(consensus.PublicKeys, consensus.leader.ConsensusPubKey)
// vrfBitmap.SetMask(bitmap)
//
// // TODO: check validity of pRnd
// newBlock.AddVrf(pRnd)
//}
rnd, blockHash, err := consensus.GetNextRnd()
// generate VRF if the current block has a new leader
if !consensus.ChainReader.IsSameLeaderAsPreviousBlock(newBlock) {
vrfBlockNumbers, err := consensus.ChainReader.ReadEpochVrfBlockNums(newBlock.Header().Epoch)
if err != nil {
consensus.getLogger().Info().
Uint64("MsgBlockNum", newBlock.NumberU64()).
Msg("[ConsensusMainLoop] no VRF block number from local db")
}
//check if VRF is already generated for the current block
vrfAlreadyGenerated := false
for _, v := range vrfBlockNumbers {
if v == newBlock.NumberU64() {
consensus.getLogger().Info().
Uint64("MsgBlockNum", newBlock.NumberU64()).
Uint64("Epoch", newBlock.Header().Epoch.Uint64()).
Msg("[ConsensusMainLoop] VRF is already generated for this block")
vrfAlreadyGenerated = true
break
}
}
if !vrfAlreadyGenerated {
//generate a new VRF for the current block
vrfBlockNumbers := consensus.GenerateVrfAndProof(newBlock, vrfBlockNumbers)
//generate a new VDF for the current epoch if there are enough VRFs in the current epoch
//note that >= instead of == is used, because it is possible the current leader
//can commit this block, go offline without finishing VDF
if (!vdfInProgress) && len(vrfBlockNumbers) >= consensus.VdfSeedSize() {
//check local database to see if there's a VDF generated for this epoch
//generate a VDF if no blocknum is available
_, err := consensus.ChainReader.ReadEpochVdfBlockNum(newBlock.Header().Epoch)
if err != nil {
consensus.GenerateVdfAndProof(newBlock, vrfBlockNumbers)
vdfInProgress = true
}
}
}
}
vdfOutput, seed, err := consensus.GetNextRnd()
if err == nil {
vdfInProgress = false
// Verify the randomness
_ = blockHash
consensus.getLogger().Info().
Bytes("rnd", rnd[:]).
Msg("[ConsensusMainLoop] Adding randomness into new block")
// newBlock.AddVdf([258]byte{}) // TODO(HB): add real vdf
vdfObject := vdf_go.New(core.ShardingSchedule.VdfDifficulty(), seed)
if !vdfObject.Verify(vdfOutput) {
consensus.getLogger().Warn().
Uint64("MsgBlockNum", newBlock.NumberU64()).
Uint64("Epoch", newBlock.Header().Epoch.Uint64()).
Msg("[ConsensusMainLoop] failed to verify the VDF output")
} else {
//write the VDF only if VDF has not been generated
_, err := consensus.ChainReader.ReadEpochVdfBlockNum(newBlock.Header().Epoch)
if err == nil {
consensus.getLogger().Info().
Uint64("MsgBlockNum", newBlock.NumberU64()).
Uint64("Epoch", newBlock.Header().Epoch.Uint64()).
Msg("[ConsensusMainLoop] VDF has already been generated previously")
} else {
consensus.getLogger().Info().
Uint64("MsgBlockNum", newBlock.NumberU64()).
Uint64("Epoch", newBlock.Header().Epoch.Uint64()).
Msg("[ConsensusMainLoop] Generated a new VDF")
newBlock.AddVdf(vdfOutput[:])
}
}
} else {
//consensus.getLogger().Info("Failed to get randomness", "error", err)
//consensus.getLogger().Error().Err(err). Msg("[ConsensusMainLoop] Failed to get randomness")
}
}
@ -1140,3 +1207,139 @@ func (consensus *Consensus) Start(blockChannel chan *types.Block, stopChan chan
}
}()
}
// GenerateVrfAndProof generates new VRF/Proof from hash of previous block
func (consensus *Consensus) GenerateVrfAndProof(newBlock *types.Block, vrfBlockNumbers []uint64) []uint64 {
sk := vrf_bls.NewVRFSigner(consensus.priKey)
blockHash := [32]byte{}
previousHeader := consensus.ChainReader.GetHeaderByNumber(newBlock.NumberU64() - 1)
previousHash := previousHeader.Hash()
copy(blockHash[:], previousHash[:])
vrf, proof := sk.Evaluate(blockHash[:])
newBlock.AddVrf(append(vrf[:], proof...))
consensus.getLogger().Info().
Uint64("MsgBlockNum", newBlock.NumberU64()).
Uint64("Epoch", newBlock.Header().Epoch.Uint64()).
Int("Num of VRF", len(vrfBlockNumbers)).
Msg("[ConsensusMainLoop] Leader generated a VRF")
return vrfBlockNumbers
}
// ValidateVrfAndProof validates a VRF/Proof from hash of previous block
func (consensus *Consensus) ValidateVrfAndProof(headerObj types.Header) bool {
vrfPk := vrf_bls.NewVRFVerifier(consensus.LeaderPubKey)
var blockHash [32]byte
previousHeader := consensus.ChainReader.GetHeaderByNumber(headerObj.Number.Uint64() - 1)
previousHash := previousHeader.Hash()
copy(blockHash[:], previousHash[:])
vrfProof := [96]byte{}
copy(vrfProof[:], headerObj.Vrf[32:])
hash, err := vrfPk.ProofToHash(blockHash[:], vrfProof[:])
if err != nil {
consensus.getLogger().Warn().
Err(err).
Str("MsgBlockNum", headerObj.Number.String()).
Msg("[OnAnnounce] VRF verification error")
return false
}
if !bytes.Equal(hash[:], headerObj.Vrf[:32]) {
consensus.getLogger().Warn().
Str("MsgBlockNum", headerObj.Number.String()).
Msg("[OnAnnounce] VRF proof is not valid")
return false
}
vrfBlockNumbers, _ := consensus.ChainReader.ReadEpochVrfBlockNums(headerObj.Epoch)
consensus.getLogger().Info().
Str("MsgBlockNum", headerObj.Number.String()).
Int("Number of VRF", len(vrfBlockNumbers)).
Msg("[OnAnnounce] validated a new VRF")
return true
}
// GenerateVdfAndProof generates new VDF/Proof from VRFs in the current epoch
func (consensus *Consensus) GenerateVdfAndProof(newBlock *types.Block, vrfBlockNumbers []uint64) {
//derive VDF seed from VRFs generated in the current epoch
seed := [32]byte{}
for i := 0; i < consensus.VdfSeedSize(); i++ {
previousVrf := consensus.ChainReader.GetVrfByNumber(vrfBlockNumbers[i])
for j := 0; j < len(seed); j++ {
seed[j] = seed[j] ^ previousVrf[j]
}
}
consensus.getLogger().Info().
Uint64("MsgBlockNum", newBlock.NumberU64()).
Uint64("Epoch", newBlock.Header().Epoch.Uint64()).
Int("Num of VRF", len(vrfBlockNumbers)).
Msg("[ConsensusMainLoop] VDF computation started")
go func() {
vdf := vdf_go.New(core.ShardingSchedule.VdfDifficulty(), seed)
outputChannel := vdf.GetOutputChannel()
start := time.Now()
vdf.Execute()
duration := time.Now().Sub(start)
consensus.getLogger().Info().
Dur("duration", duration).
Msg("[ConsensusMainLoop] VDF computation finished")
output := <-outputChannel
// The first 516 bytes are the VDF+proof and the last 32 bytes are XORed VRF as seed
rndBytes := [548]byte{}
copy(rndBytes[:516], output[:])
copy(rndBytes[516:], seed[:])
consensus.RndChannel <- rndBytes
}()
}
// ValidateVdfAndProof validates the VDF/proof in the current epoch
func (consensus *Consensus) ValidateVdfAndProof(headerObj types.Header) bool {
vrfBlockNumbers, err := consensus.ChainReader.ReadEpochVrfBlockNums(headerObj.Epoch)
if err != nil {
consensus.getLogger().Error().Err(err).
Str("MsgBlockNum", headerObj.Number.String()).
Msg("[OnAnnounce] failed to read VRF block numbers for VDF computation")
}
//extra check to make sure there's no index out of range error
//it can happen if epoch is messed up, i.e. VDF ouput is generated in the next epoch
if consensus.VdfSeedSize() > len(vrfBlockNumbers) {
return false
}
seed := [32]byte{}
for i := 0; i < consensus.VdfSeedSize(); i++ {
previousVrf := consensus.ChainReader.GetVrfByNumber(vrfBlockNumbers[i])
for j := 0; j < len(seed); j++ {
seed[j] = seed[j] ^ previousVrf[j]
}
}
vdfObject := vdf_go.New(core.ShardingSchedule.VdfDifficulty(), seed)
vdfOutput := [516]byte{}
copy(vdfOutput[:], headerObj.Vdf)
if vdfObject.Verify(vdfOutput) {
consensus.getLogger().Info().
Str("MsgBlockNum", headerObj.Number.String()).
Int("Num of VRF", consensus.VdfSeedSize()).
Msg("[OnAnnounce] validated a new VDF")
} else {
consensus.getLogger().Warn().
Str("MsgBlockNum", headerObj.Number.String()).
Uint64("Epoch", headerObj.Epoch.Uint64()).
Int("Num of VRF", consensus.VdfSeedSize()).
Msg("[OnAnnounce] VDF proof is not valid")
return false
}
return true
}

@ -57,16 +57,17 @@ var (
)
const (
bodyCacheLimit = 256
blockCacheLimit = 256
receiptsCacheLimit = 32
maxFutureBlocks = 256
maxTimeFutureBlocks = 30
badBlockLimit = 10
triesInMemory = 128
shardCacheLimit = 2
commitsCacheLimit = 10
epochCacheLimit = 10
bodyCacheLimit = 256
blockCacheLimit = 256
receiptsCacheLimit = 32
maxFutureBlocks = 256
maxTimeFutureBlocks = 30
badBlockLimit = 10
triesInMemory = 128
shardCacheLimit = 2
commitsCacheLimit = 10
epochCacheLimit = 10
randomnessCacheLimit = 10
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
BlockChainVersion = 3
@ -128,6 +129,7 @@ type BlockChain struct {
shardStateCache *lru.Cache
lastCommitsCache *lru.Cache
epochCache *lru.Cache // Cache epoch number → first block number
randomnessCache *lru.Cache // Cache for vrf/vdf
quit chan struct{} // blockchain quit channel
running int32 // running must be called atomically
@ -163,6 +165,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
shardCache, _ := lru.New(shardCacheLimit)
commitsCache, _ := lru.New(commitsCacheLimit)
epochCache, _ := lru.New(epochCacheLimit)
randomnessCache, _ := lru.New(randomnessCacheLimit)
bc := &BlockChain{
chainConfig: chainConfig,
@ -180,6 +183,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
shardStateCache: shardCache,
lastCommitsCache: commitsCache,
epochCache: epochCache,
randomnessCache: randomnessCache,
engine: engine,
vmConfig: vmConfig,
badBlocks: badBlocks,
@ -1302,6 +1306,37 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
cache, _ := bc.stateCache.TrieDB().Size()
stats.report(chain, i, cache)
//check non zero VRF field in header and add to local db
if len(block.Vrf()) > 0 {
vrfBlockNumbers, _ := bc.ReadEpochVrfBlockNums(block.Header().Epoch)
if (len(vrfBlockNumbers) > 0) && (vrfBlockNumbers[len(vrfBlockNumbers)-1] == block.NumberU64()) {
utils.Logger().Error().
Str("number", chain[i].Number().String()).
Str("epoch", block.Header().Epoch.String()).
Msg("VRF block number is already in local db")
} else {
vrfBlockNumbers = append(vrfBlockNumbers, block.NumberU64())
err = bc.WriteEpochVrfBlockNums(block.Header().Epoch, vrfBlockNumbers)
if err != nil {
utils.Logger().Error().
Str("number", chain[i].Number().String()).
Str("epoch", block.Header().Epoch.String()).
Msg("failed to write VRF block number to local db")
}
}
}
//check non zero Vdf in header and add to local db
if len(block.Vdf()) > 0 {
err = bc.WriteEpochVdfBlockNum(block.Header().Epoch, block.Number())
if err != nil {
utils.Logger().Error().
Str("number", chain[i].Number().String()).
Str("epoch", block.Header().Epoch.String()).
Msg("failed to write VDF block number to local db")
}
}
}
// Append a single chain head event if we've progressed the chain
if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() {
@ -1785,26 +1820,22 @@ func (bc *BlockChain) WriteLastCommits(lastCommits []byte) error {
}
// GetVdfByNumber retrieves the rand seed given the block number, return 0 if not exist
func (bc *BlockChain) GetVdfByNumber(number uint64) [32]byte {
func (bc *BlockChain) GetVdfByNumber(number uint64) []byte {
header := bc.GetHeaderByNumber(number)
if header == nil {
return [32]byte{}
return []byte{}
}
result := [32]byte{}
//copy(result[:], header.Vdf[:32])
// TODO: add real vdf
return result
return header.Vdf
}
// GetVrfByNumber retrieves the randomness preimage given the block number, return 0 if not exist
func (bc *BlockChain) GetVrfByNumber(number uint64) [32]byte {
func (bc *BlockChain) GetVrfByNumber(number uint64) []byte {
header := bc.GetHeaderByNumber(number)
if header == nil {
return [32]byte{}
return []byte{}
}
//return header.Vrf
// TODO: add real vrf
return [32]byte{}
return header.Vrf
}
// GetShardState returns the shard state for the given epoch,
@ -1866,6 +1897,78 @@ func (bc *BlockChain) StoreEpochBlockNumber(
return nil
}
// ReadEpochVrfBlockNums retrieves block numbers with valid VRF for the specified epoch
func (bc *BlockChain) ReadEpochVrfBlockNums(epoch *big.Int) ([]uint64, error) {
vrfNumbers := []uint64{}
if cached, ok := bc.randomnessCache.Get("vrf-" + string(epoch.Bytes())); ok {
encodedVrfNumbers := cached.([]byte)
if err := rlp.DecodeBytes(encodedVrfNumbers, &vrfNumbers); err != nil {
return nil, err
}
return vrfNumbers, nil
}
encodedVrfNumbers, err := rawdb.ReadEpochVrfBlockNums(bc.db, epoch)
if err != nil {
return nil, err
}
if err := rlp.DecodeBytes(encodedVrfNumbers, &vrfNumbers); err != nil {
return nil, err
}
return vrfNumbers, nil
}
// WriteEpochVrfBlockNums saves block numbers with valid VRF for the specified epoch
func (bc *BlockChain) WriteEpochVrfBlockNums(epoch *big.Int, vrfNumbers []uint64) error {
encodedVrfNumbers, err := rlp.EncodeToBytes(vrfNumbers)
if err != nil {
return err
}
err = rawdb.WriteEpochVrfBlockNums(bc.db, epoch, encodedVrfNumbers)
if err != nil {
return err
}
bc.randomnessCache.Add("vrf-"+string(epoch.Bytes()), encodedVrfNumbers)
return nil
}
// ReadEpochVdfBlockNum retrieves block number with valid VDF for the specified epoch
func (bc *BlockChain) ReadEpochVdfBlockNum(epoch *big.Int) (*big.Int, error) {
if cached, ok := bc.randomnessCache.Get("vdf-" + string(epoch.Bytes())); ok {
encodedVdfNumber := cached.([]byte)
return new(big.Int).SetBytes(encodedVdfNumber), nil
}
encodedVdfNumber, err := rawdb.ReadEpochVdfBlockNum(bc.db, epoch)
if err != nil {
return nil, err
}
return new(big.Int).SetBytes(encodedVdfNumber), nil
}
// WriteEpochVdfBlockNum saves block number with valid VDF for the specified epoch
func (bc *BlockChain) WriteEpochVdfBlockNum(epoch *big.Int, blockNum *big.Int) error {
err := rawdb.WriteEpochVdfBlockNum(bc.db, epoch, blockNum.Bytes())
if err != nil {
return err
}
bc.randomnessCache.Add("vdf-"+string(epoch.Bytes()), blockNum.Bytes())
return nil
}
// IsSameLeaderAsPreviousBlock retrieves a block from the database by number, caching it
func (bc *BlockChain) IsSameLeaderAsPreviousBlock(block *types.Block) bool {
if block.NumberU64() == 0 {
return false
}
previousBlock := bc.GetBlockByNumber(block.NumberU64() - 1)
return block.Coinbase() == previousBlock.Coinbase()
}
// ChainDB ...
// TODO(ricl): in eth, this is not exposed. I expose it here because I need it in Harmony object.
// In eth, chainDB is initialized within Ethereum object

@ -478,8 +478,27 @@ func ReadEpochBlockNumber(db DatabaseReader, epoch *big.Int) (*big.Int, error) {
return new(big.Int).SetBytes(data), nil
}
// WriteEpochBlockNumber stores the given epoch-number-to-epoch-block-number
// in the database.
// WriteEpochBlockNumber stores the given epoch-number-to-epoch-block-number in the database.
func WriteEpochBlockNumber(db DatabaseWriter, epoch, blockNum *big.Int) error {
return db.Put(epochBlockNumberKey(epoch), blockNum.Bytes())
}
// ReadEpochVrfBlockNums retrieves the VRF block numbers for the given epoch
func ReadEpochVrfBlockNums(db DatabaseReader, epoch *big.Int) ([]byte, error) {
return db.Get(epochVrfBlockNumbersKey(epoch))
}
// WriteEpochVrfBlockNums stores the VRF block numbers for the given epoch
func WriteEpochVrfBlockNums(db DatabaseWriter, epoch *big.Int, data []byte) error {
return db.Put(epochVrfBlockNumbersKey(epoch), data)
}
// ReadEpochVdfBlockNum retrieves the VDF block number for the given epoch
func ReadEpochVdfBlockNum(db DatabaseReader, epoch *big.Int) ([]byte, error) {
return db.Get(epochVdfBlockNumberKey(epoch))
}
// WriteEpochVdfBlockNum stores the VDF block number for the given epoch
func WriteEpochVdfBlockNum(db DatabaseWriter, epoch *big.Int, data []byte) error {
return db.Put(epochVdfBlockNumberKey(epoch), data)
}

@ -64,6 +64,12 @@ var (
// -> epoch block number (big.Int.Bytes())
epochBlockNumberPrefix = []byte("harmony-epoch-block-number-")
// epochVrfBlockNumbersPrefix + epoch (big.Int.Bytes())
epochVrfBlockNumbersPrefix = []byte("epoch-vrf-block-numbers-")
// epochVdfBlockNumberPrefix + epoch (big.Int.Bytes())
epochVdfBlockNumberPrefix = []byte("epoch-vdf-block-number-")
// Chain index prefixes (use `i` + single byte to avoid mixing data types).
BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress
@ -148,3 +154,11 @@ func shardStateKey(epoch *big.Int) []byte {
func epochBlockNumberKey(epoch *big.Int) []byte {
return append(epochBlockNumberPrefix, epoch.Bytes()...)
}
func epochVrfBlockNumbersKey(epoch *big.Int) []byte {
return append(epochVrfBlockNumbersPrefix, epoch.Bytes()...)
}
func epochVdfBlockNumberKey(epoch *big.Int) []byte {
return append(epochVdfBlockNumberPrefix, epoch.Bytes()...)
}

@ -90,6 +90,8 @@ type Header struct {
LastCommitSignature [96]byte `json:"lastCommitSignature" gencodec:"required"`
LastCommitBitmap []byte `json:"lastCommitBitmap" gencodec:"required"` // Contains which validator signed
ShardStateHash common.Hash `json:"shardStateRoot"`
Vrf []byte `json:"vrf"`
Vdf []byte `json:"vdf"`
ShardState []byte `json:"shardState"`
}
@ -276,6 +278,14 @@ func CopyHeader(h *Header) *Header {
cpy.ShardState = make([]byte, len(h.ShardState))
copy(cpy.ShardState, h.ShardState)
}
if len(h.Vrf) > 0 {
cpy.Vrf = make([]byte, len(h.Vrf))
copy(cpy.Vrf, h.Vrf)
}
if len(h.Vdf) > 0 {
cpy.Vdf = make([]byte, len(h.Vdf))
copy(cpy.Vdf, h.Vdf)
}
//if len(h.CrossLinks) > 0 {
// cpy.CrossLinks = make([]byte, len(h.CrossLinks))
// copy(cpy.CrossLinks, h.CrossLinks)
@ -383,6 +393,12 @@ func (b *Block) Header() *Header { return CopyHeader(b.header) }
// Body returns the non-header content of the block.
func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles} }
// Vdf returns header Vdf.
func (b *Block) Vdf() []byte { return common.CopyBytes(b.header.Vdf) }
// Vrf returns header Vrf.
func (b *Block) Vrf() []byte { return common.CopyBytes(b.header.Vrf) }
// Size returns the true RLP encoded storage size of the block, either by encoding
// and returning it, or returning a previsouly cached value.
func (b *Block) Size() common.StorageSize {
@ -485,15 +501,15 @@ func Number(b1, b2 *Block) bool {
return b1.header.Number.Cmp(b2.header.Number) < 0
}
//// AddVdf add vdf into block header
//func (b *Block) AddVdf(vdf [258]byte) {
// b.header.Vdf = vdf
//}
//
//// AddVrf add vrf into block header
//func (b *Block) AddVrf(vrf [32]byte) {
// b.header.Vrf = vrf
//}
// AddVrf add vrf into block header
func (b *Block) AddVrf(vrf []byte) {
b.header.Vrf = vrf
}
// AddVdf add vdf into block header
func (b *Block) AddVdf(vdf []byte) {
b.header.Vdf = vdf
}
// AddShardState add shardState into block header
func (b *Block) AddShardState(shardState ShardState) error {

@ -22,6 +22,7 @@ require (
github.com/gorilla/mux v1.7.2
github.com/harmony-ek/gencodec v0.0.0-20190215044613-e6740dbdd846
github.com/harmony-one/bls v0.0.5
github.com/harmony-one/vdf v1.0.0
github.com/hashicorp/golang-lru v0.5.1
github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365
github.com/ipfs/go-datastore v0.0.5

@ -32,6 +32,10 @@ func (s fixedSchedule) IsLastBlock(blockNum uint64) bool {
return blockNum%blocks == blocks-1
}
func (s fixedSchedule) VdfDifficulty() int {
return mainnetVdfDifficulty
}
// NewFixedSchedule returns a sharding configuration schedule that uses the
// given config instance for all epochs. Useful for testing.
func NewFixedSchedule(instance Instance) Schedule {

@ -18,6 +18,8 @@ const (
localnetEpochBlock1 = 10
twoOne = 5
localnetVdfDifficulty = 5000 // This takes about 10s to finish the vdf
)
func (localnetSchedule) InstanceForEpoch(epoch *big.Int) Instance {
@ -57,6 +59,10 @@ func (ls localnetSchedule) IsLastBlock(blockNum uint64) bool {
}
}
func (ls localnetSchedule) VdfDifficulty() int {
return localnetVdfDifficulty
}
var localnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(localnetV1Epoch), big.NewInt(localnetV2Epoch)}
var localnetV0 = MustNewInstance(2, 7, 5, genesis.LocalHarmonyAccounts, genesis.LocalFnAccounts, localnetReshardingEpoch)

@ -10,6 +10,8 @@ const (
mainnetEpochBlock1 = 344064 // 21 * 2^14
blocksPerShard = 16384 // 2^14
mainnetV1Epoch = 1
mainnetVdfDifficulty = 50000 // This takes about 100s to finish the vdf
)
// MainnetSchedule is the mainnet sharding configuration schedule.
@ -53,6 +55,10 @@ func (ms mainnetSchedule) IsLastBlock(blockNum uint64) bool {
}
}
func (ms mainnetSchedule) VdfDifficulty() int {
return mainnetVdfDifficulty
}
var mainnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(mainnetV1Epoch)}
var mainnetV0 = MustNewInstance(4, 150, 112, genesis.HarmonyAccounts, genesis.FoundationalNodeAccounts, mainnetReshardingEpoch)
var mainnetV1 = MustNewInstance(4, 152, 112, genesis.HarmonyAccounts, genesis.FoundationalNodeAccountsV1, mainnetReshardingEpoch)

@ -21,6 +21,9 @@ type Schedule interface {
// IsLastBlock check if the block is the last block in the epoch
IsLastBlock(blockNum uint64) bool
// VDFDifficulty returns number of iterations for VDF calculation
VdfDifficulty() int
}
// Instance is one sharding configuration instance.

@ -18,6 +18,8 @@ const (
testnetEpochBlock1 = 78
threeOne = 111
testnetVdfDifficulty = 10000 // This takes about 20s to finish the vdf
)
func (testnetSchedule) InstanceForEpoch(epoch *big.Int) Instance {
@ -58,6 +60,10 @@ func (ts testnetSchedule) IsLastBlock(blockNum uint64) bool {
}
}
func (ts testnetSchedule) VdfDifficulty() int {
return testnetVdfDifficulty
}
var testnetReshardingEpoch = []*big.Int{big.NewInt(0), big.NewInt(testnetV1Epoch), big.NewInt(testnetV2Epoch)}
var testnetV0 = MustNewInstance(2, 150, 150, genesis.TNHarmonyAccounts, genesis.TNFoundationalAccounts, testnetReshardingEpoch)

Loading…
Cancel
Save