-
Notifications
You must be signed in to change notification settings - Fork 1
/
core.go
155 lines (133 loc) · 4.98 KB
/
core.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package blockchain
import (
"context"
"fmt"
"math"
"sync"
"time"
"github.com/ovcharovvladimir/Prysm/beacon-chain/params"
"github.com/ovcharovvladimir/Prysm/beacon-chain/powchain"
"github.com/ovcharovvladimir/Prysm/beacon-chain/types"
"github.com/ovcharovvladimir/Prysm/beacon-chain/utils"
"github.com/ovcharovvladimir/essentiaHybrid/common"
"github.com/ovcharovvladimir/essentiaHybrid/essdb"
"github.com/ovcharovvladimir/essentiaHybrid/rlp"
"github.com/sirupsen/logrus"
)
var stateLookupKey = "beaconchainstate"
// BeaconChain represents the core PoS blockchain object containing
// both a crystallized and active state.
type BeaconChain struct {
state *beaconState
lock sync.Mutex
db essdb.Database
}
type beaconState struct {
ActiveState *types.ActiveState
CrystallizedState *types.CrystallizedState
}
// NewBeaconChain initializes an instance using genesis state parameters if
// none provided.
func NewBeaconChain(db essdb.Database) (*BeaconChain, error) {
beaconChain := &BeaconChain{
db: db,
state: &beaconState{},
}
has, err := db.Has([]byte(stateLookupKey))
if err != nil {
return nil, err
}
if !has {
log.Info("No chainstate found on disk, initializing beacon from genesis")
active, crystallized := types.NewGenesisStates()
beaconChain.state.ActiveState = active
beaconChain.state.CrystallizedState = crystallized
return beaconChain, nil
}
enc, err := db.Get([]byte(stateLookupKey))
if err != nil {
return nil, err
}
// Deserializes the encoded object into a beacon chain.
if err := rlp.DecodeBytes(enc, &beaconChain.state); err != nil {
return nil, fmt.Errorf("could not deserialize chainstate from disk: %v", err)
}
return beaconChain, nil
}
// ActiveState exposes a getter to external services.
func (b *BeaconChain) ActiveState() *types.ActiveState {
return b.state.ActiveState
}
// CrystallizedState exposes a getter to external services.
func (b *BeaconChain) CrystallizedState() *types.CrystallizedState {
return b.state.CrystallizedState
}
// GenesisBlock returns the canonical, genesis block.
func (b *BeaconChain) GenesisBlock() *types.Block {
return types.NewGenesisBlock()
}
// MutateActiveState allows external services to modify the active state.
func (b *BeaconChain) MutateActiveState(activeState *types.ActiveState) error {
defer b.lock.Unlock()
b.lock.Lock()
b.state.ActiveState = activeState
return b.persist()
}
// MutateCrystallizedState allows external services to modify the crystallized state.
func (b *BeaconChain) MutateCrystallizedState(crystallizedState *types.CrystallizedState) error {
defer b.lock.Unlock()
b.lock.Lock()
b.state.CrystallizedState = crystallizedState
return b.persist()
}
// CanProcessBlock decides if an incoming p2p block can be processed into the chain's block trie.
func (b *BeaconChain) CanProcessBlock(fetcher powchain.POWBlockFetcher, block *types.Block) (bool, error) {
mainchainBlock, err := fetcher.BlockByHash(context.Background(), block.Data().MainChainRef)
if err != nil {
return false, err
}
// There needs to be a valid mainchain block for the reference hash in a beacon block.
if mainchainBlock == nil {
return false, nil
}
// TODO: check if the parentHash pointed by the beacon block is in the beaconDB.
// Calculate the timestamp validity condition.
slotDuration := time.Duration(block.Data().SlotNumber*params.SlotLength) * time.Second
validTime := time.Now().After(b.GenesisBlock().Data().Timestamp.Add(slotDuration))
return validTime, nil
}
// persist stores the RLP encoding of the latest beacon chain state into the db.
func (b *BeaconChain) persist() error {
encodedState, err := rlp.EncodeToBytes(b.state)
if err != nil {
return err
}
return b.db.Put([]byte(stateLookupKey), encodedState)
}
// computeNewActiveState computes a new active state for every beacon block.
func (b *BeaconChain) computeNewActiveState(seed common.Hash) (*types.ActiveState, error) {
attesters, proposer, err := b.getAttestersProposer(seed)
if err != nil {
return nil, err
}
// TODO: Verify attestations from attesters.
log.WithFields(logrus.Fields{"attestersIndices": attesters}).Debug("Attester indices")
// TODO: Verify main signature from proposer.
log.WithFields(logrus.Fields{"proposerIndex": proposer}).Debug("Proposer index")
// TODO: Update crosslink records (post Ruby release).
// TODO: Track reward for the proposer that just proposed the latest beacon block.
// TODO: Verify randao reveal from validator's hash pre image.
return &types.ActiveState{
TotalAttesterDeposits: 0,
AttesterBitfields: []byte{},
}, nil
}
// getAttestersProposer returns lists of random sampled attesters and proposer indices.
func (b *BeaconChain) getAttestersProposer(seed common.Hash) ([]int, int, error) {
attesterCount := math.Min(params.AttesterCount, float64(len(b.CrystallizedState().ActiveValidators)))
indices, err := utils.ShuffleIndices(seed, len(b.CrystallizedState().ActiveValidators))
if err != nil {
return nil, -1, err
}
return indices[:int(attesterCount)], indices[len(indices)-1], nil
}