func NewReadableBlockBody(b *coin.Block) ReadableBlockBody { txns := make([]ReadableTransaction, len(b.Body.Transactions)) for i := range b.Body.Transactions { if b.Seq() == uint64(0) { // genesis block txns[i] = NewGenesisReadableTransaction(&Transaction{Txn: b.Body.Transactions[i]}) } else { txns[i] = NewReadableTransaction(&Transaction{Txn: b.Body.Transactions[i]}) } } return ReadableBlockBody{ Transactions: txns, } }
// ProcessBlock will index the transaction, outputs,etc. func (hd *HistoryDB) ProcessBlock(b *coin.Block) error { // index the transactions for _, t := range b.Body.Transactions { tx := Transaction{ Tx: t, BlockSeq: b.Seq(), } if err := hd.txns.Add(&tx); err != nil { return err } // handle tx in, genesis transaction's vin is empty, so should be ignored. if b.Seq() > 0 { for _, in := range t.In { o, err := hd.outputs.Get(in) if err != nil { return err } // update output's spent block seq and txid. o.SpentBlockSeq = b.Seq() o.SpentTxID = t.Hash() if err := hd.outputs.Set(*o); err != nil { return err } } } // handle the tx out uxArray := coin.CreateUnspents(b.Head, t) for _, ux := range uxArray { uxOut := UxOut{ Out: ux, } if err := hd.outputs.Set(uxOut); err != nil { return err } if err := hd.addrUx.Add(ux.Body.Address, ux.Hash()); err != nil { return err } } } return nil }
// RemoveBlock remove block from blocks bucket and tree bucket. // can't remove block if it has children. func (bt *BlockTree) RemoveBlock(b *coin.Block) error { return UpdateTx(func(tx *bolt.Tx) error { // delete block in blocks bucket. blocks := tx.Bucket(bt.blocks.Name) hash := b.HashHeader() if err := blocks.Delete(hash[:]); err != nil { return err } // get tree bucket. tree := tx.Bucket(bt.tree.Name) // check if this block has children has, err := hasChild(tree, *b) if err != nil { return err } if has { return errHasChild } // get block hash pairs in depth hashPairs, err := getHashPairInDepth(tree, b.Seq(), func(hp coin.HashPair) bool { return true }) if err != nil { return err } // remove block hash pair in tree. ps := removePairs(hashPairs, coin.HashPair{hash, b.PreHashHeader()}) if len(ps) == 0 { tree.Delete(itob(b.Seq())) return nil } // update the hash pairs in tree. return setHashPairInDepth(tree, b.Seq(), ps) }) }
// AddBlock write the block into blocks bucket, add the pair of block hash and pre block hash into // tree in the block depth. func (bt *BlockTree) AddBlock(b *coin.Block) error { return UpdateTx(func(tx *bolt.Tx) error { blocks := tx.Bucket(bt.blocks.Name) // can't store block if it's not genesis block and has no parent. if b.Seq() > 0 && b.PreHashHeader() == emptyHash { return errNoParent } // check if the block already exist. hash := b.HashHeader() if blk := blocks.Get(hash[:]); blk != nil { return errBlockExist } // write block into blocks bucket. if err := setBlock(blocks, b); err != nil { return err } // get tree bucket. tree := tx.Bucket(bt.tree.Name) // the pre hash must be in depth - 1. if b.Seq() > 0 { preHash := b.PreHashHeader() parentHashPair, err := getHashPairInDepth(tree, b.Seq()-1, func(hp coin.HashPair) bool { return hp.Hash == preHash }) if err != nil { return err } if len(parentHashPair) == 0 { return errWrongParent } } hp := coin.HashPair{hash, b.Head.PrevHash} // get block pairs in the depth hashPairs, err := getHashPairInDepth(tree, b.Seq(), allPairs) if err != nil { return err } if len(hashPairs) == 0 { // no hash pair exist in the depth. // write the hash pair into tree. return setHashPairInDepth(tree, b.Seq(), []coin.HashPair{hp}) } // check dup block if containHash(hashPairs, hp) { return errBlockExist } hashPairs = append(hashPairs, hp) return setHashPairInDepth(tree, b.Seq(), hashPairs) }) }