Skip to content

Commit

Permalink
store all ticket id in storage and hash in mixdigest
Browse files Browse the repository at this point in the history
  • Loading branch information
zongyuan committed Jun 12, 2019
1 parent ed23b49 commit 116000a
Show file tree
Hide file tree
Showing 14 changed files with 150 additions and 77 deletions.
2 changes: 1 addition & 1 deletion cmd/efsn/chaincmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ func dump(ctx *cli.Context) error {
fmt.Println("{}")
utils.Fatalf("block not found")
} else {
state, err := state.New(block.Root(), state.NewDatabase(chainDb))
state, err := state.New(block.Root(), block.MixDigest(), state.NewDatabase(chainDb))
if err != nil {
utils.Fatalf("could not create new state: %v", err)
}
Expand Down
43 changes: 40 additions & 3 deletions common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -834,13 +834,50 @@ func (s TicketSlice) ToMap() map[Hash]TicketDisplay {
}

func (s TicketSlice) DeepCopy() TicketSlice {
r := make(TicketSlice, 0, len(s))
for _, t := range s {
r = append(r, t)
r := make(TicketSlice, len(s))
for i, t := range s {
r[i] = t
}
return r
}

func (s TicketSlice) AllIds() []Hash {
ids := make([]Hash, len(s))
for i, t := range s {
ids[i] = t.ID
}
return ids
}

func (s TicketSlice) Get(id Hash) (*Ticket, error) {
for _, t := range s {
if t.ID == id {
return &t, nil
}
}
return nil, fmt.Errorf("%v ticket not fount", id.String())
}

func (s TicketSlice) AddTicket(ticket *Ticket) (TicketSlice, error) {
for _, t := range s {
if t.ID == ticket.ID {
return s, fmt.Errorf("AddTicket: %v ticket exist", t.ID.String())
}
}
s = append(s, *ticket)
return s, nil
}

func (s TicketSlice) RemoveTicket(id Hash) (TicketSlice, error) {
for i, t := range s {
if t.ID == id {
s = append(s[:i], s[i+1:]...)
return s, nil
}
}
return nil, fmt.Errorf("RemoveTicket: %v ticket not fount", id.String())
}

// Swap wacom
type Swap struct {
ID Hash
Expand Down
31 changes: 14 additions & 17 deletions consensus/datong/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,19 +227,15 @@ func (dt *DaTong) verifySeal(chain consensus.ChainReader, header *types.Header,
return err
}
ticketID := snap.GetVoteTicket()
ticket, err := dt.getTicket(parent, ticketID)
if err != nil {
return err
}
// verify ticket with signer
if header.Coinbase != ticket.Owner() {
return errors.New("Coinbase is not the voted ticket owner")
}
// verify ticket: list squence, ID , ticket Info, difficulty
diff, tk, listSq, _, errv := dt.calcBlockDifficulty(chain, header, parent)
if errv != nil {
return errv
}
// verify ticket with signer
if tk.Owner() != header.Coinbase {
return errors.New("Coinbase is not the voted ticket owner")
}
// check ticket ID
if tk.ID != ticketID {
return fmt.Errorf("verifySeal ticketID mismatch, have %v, want %v", ticketID.String(), tk.ID.String())
Expand Down Expand Up @@ -404,6 +400,15 @@ func (dt *DaTong) Finalize(chain consensus.ChainReader, header *types.Header, st
log.Warn("Next block have no ticket, wait buy ticket.")
return nil, errors.New("Next block have no ticket, wait buy ticket.")
}
ticketsIDHash, err := headerState.UpdateTickets()
if err != nil {
return nil, errors.New("UpdateTickets failed")
}
if header.MixDigest == (common.Hash{}) {
header.MixDigest = ticketsIDHash
} else if header.MixDigest != ticketsIDHash {
return nil, fmt.Errorf("verify MixDigest failed, have %v, want %v", header.MixDigest, ticketsIDHash)
}

snap.SetWeight(remainingWeight)
snap.SetTicketWeight(remainingWeight)
Expand Down Expand Up @@ -517,16 +522,8 @@ func (dt *DaTong) Close() error {
return nil
}

func (dt *DaTong) getTicket(header *types.Header, id common.Hash) (*common.Ticket, error) {
statedb, err := state.New(header.Root, dt.stateCache)
if err != nil {
return nil, fmt.Errorf("getTicket error:%v", err)
}
return statedb.GetTicket(id)
}

func (dt *DaTong) getAllTickets(header *types.Header) (common.TicketSlice, error) {
statedb, err := state.New(header.Root, dt.stateCache)
statedb, err := state.New(header.Root, header.MixDigest, dt.stateCache)
if err != nil {
return nil, fmt.Errorf("getAllTickets error:%v", err)
}
Expand Down
12 changes: 6 additions & 6 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
bc.currentBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64()))
}
if currentBlock := bc.CurrentBlock(); currentBlock != nil {
if _, err := state.New(currentBlock.Root(), bc.stateCache); err != nil {
if _, err := bc.State(); err != nil {
// Rewound state missing, rolled back to before pivot, reset to genesis
bc.currentBlock.Store(bc.genesisBlock)
}
Expand Down Expand Up @@ -378,12 +378,12 @@ func (bc *BlockChain) Processor() Processor {

// State returns a new mutable state based on the current HEAD block.
func (bc *BlockChain) State() (*state.StateDB, error) {
return bc.StateAt(bc.CurrentBlock().Root())
return bc.StateAt(bc.CurrentBlock().Root(), bc.CurrentBlock().MixDigest())
}

// StateAt returns a new mutable state based on a particular point in time.
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
return state.New(root, bc.stateCache)
func (bc *BlockChain) StateAt(root common.Hash, mixDigest common.Hash) (*state.StateDB, error) {
return state.New(root, mixDigest, bc.stateCache)
}

// Reset purges the entire blockchain, restoring it to its genesis state.
Expand Down Expand Up @@ -428,7 +428,7 @@ func (bc *BlockChain) repair(head **types.Block) error {
for {
blockNumber := (*head).Number()
// Abort if we've rewound to a head block that does have associated state
if _, err := state.New((*head).Root(), bc.stateCache); err == nil {
if _, err := bc.StateAt((*head).Root(), (*head).MixDigest()); err == nil {
if rewound {
log.Info("Rewound blockchain to past state", "number", blockNumber, "hash", (*head).Hash())
}
Expand Down Expand Up @@ -1174,7 +1174,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
} else {
parent = chain[i-1]
}
state, err := state.New(parent.Root(), bc.stateCache)
state, err := bc.StateAt(parent.Root(), parent.MixDigest())
if err != nil {
return i, events, coalescedLogs, err
}
Expand Down
2 changes: 1 addition & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
return nil, nil
}
for i := 0; i < n; i++ {
statedb, err := state.New(parent.Root(), state.NewDatabase(db))
statedb, err := state.New(parent.Root(), parent.MixDigest(), state.NewDatabase(db))
if err != nil {
panic(err)
}
Expand Down
6 changes: 4 additions & 2 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
if db == nil {
db = ethdb.NewMemDatabase()
}
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
statedb, _ := state.New(common.Hash{}, common.Hash{}, state.NewDatabase(db))
for addr, account := range g.Alloc {
statedb.AddBalance(addr, common.SystemAssetID, account.Balance)
statedb.SetCode(addr, account.Code)
Expand All @@ -246,6 +246,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
blockNumber := new(big.Int).SetUint64(g.Number)
timestamp := new(big.Int).SetUint64(g.Timestamp)

var ticketsIDHash common.Hash
if g.TicketCreateInfo != nil {
var x uint64
for x = 0; x < g.TicketCreateInfo.Count; x++ {
Expand All @@ -257,6 +258,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
}
statedb.AddTicket(ticket)
}
ticketsIDHash, _ = statedb.UpdateTickets()
}

statedb.GenAsset(common.SystemAsset)
Expand All @@ -271,7 +273,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
GasLimit: g.GasLimit,
GasUsed: g.GasUsed,
Difficulty: g.Difficulty,
MixDigest: g.Mixhash,
MixDigest: ticketsIDHash,
Coinbase: g.Coinbase,
Root: root,
}
Expand Down
3 changes: 0 additions & 3 deletions core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -479,9 +479,6 @@ func (s *stateObject) setTimeLockBalance(assetID common.Hash, amount *common.Tim
func (c *stateObject) ReturnGas(gas *big.Int) {}

func (self *stateObject) deepCopy(db *StateDB) *stateObject {
if self.address == common.TicketKeyAddress {
self.CommitTrie(db.db)
}
stateObject := newObject(db, self.address, self.data)
if self.trie != nil {
stateObject.trie = db.db.CopyTrie(self.trie)
Expand Down
107 changes: 73 additions & 34 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,25 +81,31 @@ type StateDB struct {
validRevisions []revision
nextRevisionId int

ticketsHash common.Hash
tickets common.TicketSlice

lock sync.Mutex
rwlock sync.RWMutex
}

// Create a new state from a given trie.
func New(root common.Hash, db Database) (*StateDB, error) {
func New(root common.Hash, mixDigest common.Hash, db Database) (*StateDB, error) {
tr, err := db.OpenTrie(root)
if err != nil {
return nil, err
}
return &StateDB{
statedb := &StateDB{
db: db,
trie: tr,
stateObjects: make(map[common.Address]*stateObject),
stateObjectsDirty: make(map[common.Address]struct{}),
logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
}, nil
ticketsHash: mixDigest,
tickets: nil,
}
return statedb, nil
}

// setError remembers the first non-nil error it is called with.
Expand Down Expand Up @@ -130,6 +136,7 @@ func (self *StateDB) Reset(root common.Hash) error {
self.logSize = 0
self.preimages = make(map[common.Hash][]byte)
self.clearJournalAndRefund()
self.tickets = nil
return nil
}

Expand Down Expand Up @@ -570,6 +577,8 @@ func (self *StateDB) Copy() *StateDB {
logSize: self.logSize,
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
ticketsHash: self.ticketsHash,
tickets: self.tickets.DeepCopy(),
}
// Copy the dirty states, logs, and preimages
for addr := range self.journal.dirties {
Expand Down Expand Up @@ -961,7 +970,13 @@ func (db *StateDB) setTicketState(key, value common.Hash) {

// IsTicketExist wacom
func (db *StateDB) IsTicketExist(id common.Hash) bool {
_, err := db.GetTicket(id)
tickets, err := db.AllTickets()
if err != nil {
log.Error("IsTicketExist unable to retrieve all tickets")
return false
}

_, err = tickets.Get(id)
return err == nil
}

Expand All @@ -983,58 +998,82 @@ func (db *StateDB) GetTicket(id common.Hash) (*common.Ticket, error) {

// AllTickets wacom
func (db *StateDB) AllTickets() (common.TicketSlice, error) {
if len(db.tickets) != 0 {
return db.tickets, nil
}

db.rwlock.RLock()
defer db.rwlock.RUnlock()

stateObject := db.getStateObject(common.TicketKeyAddress)
if stateObject == nil {
return nil, nil
key := db.ticketsHash
blob := db.GetStructData(common.TicketKeyAddress, key.Bytes())
if len(blob) == 0 {
return common.TicketSlice{}, nil
}
tickets := make(common.TicketSlice, 0, 1000)
tr := stateObject.getTrie(db.db)
it := trie.NewIterator(tr.NodeIterator(nil))
emptyKey := common.Hash{}
for it.Next() {
key := common.BytesToHash(tr.GetKey(it.Key))
if key == emptyKey {
continue
}
value, dirty := stateObject.dirtyStorage[key]
if !dirty {
if _, content, _, err := rlp.Split(it.Value); err == nil {
value = common.BytesToHash(content)
}
}
if ticket, err := common.ParseTicket(key, value); err == nil {
tickets = append(tickets, *ticket)
var ids []common.Hash
if err := rlp.DecodeBytes(blob, &ids); err != nil {
log.Error("AllTickets: Unable to decode tickets " + key.String())
return nil, fmt.Errorf("Unable to decode tickets, err: %v", err)
}
tickets := make(common.TicketSlice, len(ids))
for i, id := range ids {
ticket, err := db.GetTicket(id)
if err != nil {
log.Error("AllTickets error: " + err.Error())
return nil, fmt.Errorf("AllTickets error: %v", err)
}
tickets[i] = *ticket
}
return tickets, nil
db.tickets = tickets
return db.tickets, nil
}

// AddTicket wacom
func (db *StateDB) AddTicket(ticket common.Ticket) error {
id := ticket.ID
if id == (common.Hash{}) {
return fmt.Errorf("AddTicket: empty ticket ID")
tickets, err := db.AllTickets()
if err != nil {
return fmt.Errorf("AddTicket error: %v", err)
}
if db.IsTicketExist(id) == true {
return fmt.Errorf("AddTicket: %s Ticket exists", id.String())
tickets, err = tickets.AddTicket(&ticket)
if err != nil {
return fmt.Errorf("AddTicket error: %v", err)
}
db.tickets = tickets
value := ticket.ToValHash()
db.setTicketState(id, value)
db.setTicketState(ticket.ID, value)
return nil
}

// RemoveTicket wacom
func (db *StateDB) RemoveTicket(id common.Hash) error {
if db.IsTicketExist(id) == false {
return fmt.Errorf("RemoveTicket: %s Ticket not found", id.String())
tickets, err := db.AllTickets()
if err != nil {
return fmt.Errorf("RemoveTicket error: %v", err)
}
tickets, err = tickets.RemoveTicket(id)
if err != nil {
return fmt.Errorf("RemoveTicket error: %v", err)
}
db.setTicketState(id, common.Hash{})
db.tickets = tickets
return nil
}

func (db *StateDB) UpdateTickets() (common.Hash, error) {
ids := db.tickets.AllIds()
blob, err := rlp.EncodeToBytes(&ids)
if err != nil {
log.Error("UpdateTickets: Unable to encode tickets")
return common.Hash{}, fmt.Errorf("Unable to encode tickets, err: %v", err)
}
hash := crypto.Keccak256Hash(blob)

db.rwlock.Lock()
defer db.rwlock.Unlock()

db.SetStructData(common.TicketKeyAddress, hash.Bytes(), blob)
return hash, nil
}

// AllSwaps wacom
func (db *StateDB) AllSwaps() (map[common.Hash]common.Swap, error) {
return nil, fmt.Errorf("AllSwaps has been depreciated please use api.fusionnetwork.io")
Expand Down
Loading

0 comments on commit 116000a

Please sign in to comment.