OSDN Git Service

Cache utxos (#169)
authoricodezjb <icodezjb@163.com>
Tue, 5 Dec 2017 01:36:23 +0000 (09:36 +0800)
committerGuanghua Guo <1536310027@qq.com>
Tue, 5 Dec 2017 01:36:23 +0000 (09:36 +0800)
* Cache the account utxos

* Remove IndexAssets

blockchain/account/accounts.go
blockchain/account/builder.go
blockchain/account/reserve.go
blockchain/asset/asset.go
blockchain/asset/block.go
blockchain/hsm_test.go
blockchain/wallet/wallet.go
node/node.go

index b5a9eb6..83f1705 100755 (executable)
@@ -47,11 +47,11 @@ func accountCPKey(hash [32]byte) []byte {
 }
 
 // NewManager creates a new account manager
-func NewManager(db, walletDB dbm.DB, walletHeightFn func() uint64, chain *protocol.Chain) *Manager {
+func NewManager(db, walletDB dbm.DB, chain *protocol.Chain) *Manager {
        return &Manager{
                db:          db,
                chain:       chain,
-               utxoDB:      newReserver(chain, walletDB, walletHeightFn),
+               utxoDB:      newReserver(chain, walletDB),
                cache:       lru.New(maxAccountCache),
                aliasCache:  lru.New(maxAccountCache),
                delayedACPs: make(map[*txbuilder.TemplateBuilder][]*controlProgram),
index 60ad44d..701543d 100644 (file)
@@ -59,7 +59,7 @@ func (a *spendAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) e
                AssetID:   *a.AssetId,
                AccountID: a.AccountID,
        }
-       res, err := a.accounts.utxoDB.Reserve(ctx, src, a.Amount, a.ClientToken, b.MaxTime())
+       res, err := a.accounts.utxoDB.Reserve(src, a.Amount, a.ClientToken, b.MaxTime())
        if err != nil {
                return errors.Wrap(err, "reserving utxos")
        }
@@ -68,7 +68,7 @@ func (a *spendAction) Build(ctx context.Context, b *txbuilder.TemplateBuilder) e
        b.OnRollback(canceler(ctx, a.accounts, res.ID))
 
        for _, r := range res.UTXOs {
-               txInput, sigInst, err := utxoToInputs(ctx, acct, r, a.ReferenceData)
+               txInput, sigInst, err := utxoToInputs(acct, r, a.ReferenceData)
                if err != nil {
                        return errors.Wrap(err, "creating inputs")
                }
@@ -138,7 +138,7 @@ func (a *spendUTXOAction) Build(ctx context.Context, b *txbuilder.TemplateBuilde
                }
        }
 
-       txInput, sigInst, err := utxoToInputs(ctx, acct, res.UTXOs[0], a.ReferenceData)
+       txInput, sigInst, err := utxoToInputs(acct, res.UTXOs[0], a.ReferenceData)
        if err != nil {
                return err
        }
@@ -155,7 +155,7 @@ func canceler(ctx context.Context, m *Manager, rid uint64) func() {
        }
 }
 
-func utxoToInputs(ctx context.Context, account *signers.Signer, u *utxo, refData []byte) (
+func utxoToInputs(account *signers.Signer, u *utxo, refData []byte) (
        *legacy.TxInput,
        *txbuilder.SigningInstruction,
        error,
index 631309c..7d2e554 100755 (executable)
@@ -12,8 +12,8 @@ import (
        log "github.com/sirupsen/logrus"
        dbm "github.com/tendermint/tmlibs/db"
 
-       "github.com/bytom/errors"
        "github.com/bytom/config"
+       "github.com/bytom/errors"
        "github.com/bytom/protocol"
        "github.com/bytom/protocol/bc"
        "github.com/bytom/sync/idempotency"
@@ -74,11 +74,10 @@ type reservation struct {
        ClientToken *string
 }
 
-func newReserver(c *protocol.Chain, walletdb dbm.DB, walletHeightFn func() uint64) *reserver {
+func newReserver(c *protocol.Chain, walletdb dbm.DB) *reserver {
        return &reserver{
                c:            c,
                db:           walletdb,
-               heightFn:     walletHeightFn,
                reservations: make(map[uint64]*reservation),
                sources:      make(map[source]*sourceReserver),
        }
@@ -97,7 +96,6 @@ func newReserver(c *protocol.Chain, walletdb dbm.DB, walletHeightFn func() uint6
 type reserver struct {
        c                 *protocol.Chain
        db                dbm.DB
-       heightFn          func() uint64
        nextReservationID uint64
        idempotency       idempotency.Group
 
@@ -110,24 +108,24 @@ type reserver struct {
 
 // Reserve selects and reserves UTXOs according to the criteria provided
 // in source. The resulting reservation expires at exp.
-func (re *reserver) Reserve(ctx context.Context, src source, amount uint64, clientToken *string, exp time.Time) (*reservation, error) {
+func (re *reserver) Reserve(src source, amount uint64, clientToken *string, exp time.Time) (*reservation, error) {
 
        if clientToken == nil {
-               return re.reserve(ctx, src, amount, clientToken, exp)
+               return re.reserve(src, amount, clientToken, exp)
        }
 
        untypedRes, err := re.idempotency.Once(*clientToken, func() (interface{}, error) {
-               return re.reserve(ctx, src, amount, clientToken, exp)
+               return re.reserve(src, amount, clientToken, exp)
        })
        return untypedRes.(*reservation), err
 }
 
-func (re *reserver) reserve(ctx context.Context, src source, amount uint64, clientToken *string, exp time.Time) (res *reservation, err error) {
+func (re *reserver) reserve(src source, amount uint64, clientToken *string, exp time.Time) (res *reservation, err error) {
        sourceReserver := re.source(src)
 
        // Try to reserve the right amount.
        rid := atomic.AddUint64(&re.nextReservationID, 1)
-       reserved, total, err := sourceReserver.reserve(ctx, rid, amount)
+       reserved, total, err := sourceReserver.reserve(rid, amount)
        if err != nil {
                return nil, err
        }
@@ -166,7 +164,7 @@ func (re *reserver) ReserveUTXO(ctx context.Context, out bc.Hash, clientToken *s
 }
 
 func (re *reserver) reserveUTXO(ctx context.Context, out bc.Hash, exp time.Time, clientToken *string) (*reservation, error) {
-       u, err := findSpecificUTXO(ctx, re.db, out)
+       u, err := findSpecificUTXO(re.db, out)
        if err != nil {
                return nil, err
        }
@@ -259,7 +257,6 @@ func (re *reserver) source(src source) *sourceReserver {
                db:       re.db,
                src:      src,
                validFn:  re.checkUTXO,
-               heightFn: re.heightFn,
                cached:   make(map[bc.Hash]*utxo),
                reserved: make(map[bc.Hash]uint64),
        }
@@ -271,22 +268,19 @@ type sourceReserver struct {
        db       dbm.DB
        src      source
        validFn  func(u *utxo) bool
-       heightFn func() uint64
-
-       mu         sync.Mutex
-       cached     map[bc.Hash]*utxo
-       reserved   map[bc.Hash]uint64
-       lastHeight uint64
+       mu       sync.Mutex
+       cached   map[bc.Hash]*utxo
+       reserved map[bc.Hash]uint64
 }
 
-func (sr *sourceReserver) reserve(ctx context.Context, rid uint64, amount uint64) ([]*utxo, uint64, error) {
+func (sr *sourceReserver) reserve(rid uint64, amount uint64) ([]*utxo, uint64, error) {
        reservedUTXOs, reservedAmount, err := sr.reserveFromCache(rid, amount)
        if err == nil {
                return reservedUTXOs, reservedAmount, nil
        }
 
        // Find the set of UTXOs that match this source.
-       err = sr.refillCache(ctx)
+       err = sr.refillCache()
        if err != nil {
                return nil, 0, err
        }
@@ -362,25 +356,14 @@ func (sr *sourceReserver) cancel(res *reservation) {
        }
 }
 
-func (sr *sourceReserver) refillCache(ctx context.Context) error {
-       sr.mu.Lock()
-       lastHeight := sr.lastHeight
-       sr.mu.Unlock()
-
-       curHeight := sr.heightFn()
-       if lastHeight >= curHeight {
-               return nil
-       }
+func (sr *sourceReserver) refillCache() error {
 
-       utxos, err := findMatchingUTXOs(ctx, sr.db, sr.src)
+       utxos, err := findMatchingUTXOs(sr.db, sr.src)
        if err != nil {
                return errors.Wrap(err)
        }
 
        sr.mu.Lock()
-       if curHeight > sr.lastHeight {
-               sr.lastHeight = curHeight
-       }
        for _, u := range utxos {
                sr.cached[u.OutputID] = u
        }
@@ -389,7 +372,7 @@ func (sr *sourceReserver) refillCache(ctx context.Context) error {
        return nil
 }
 
-func findMatchingUTXOs(ctx context.Context, db dbm.DB, src source) ([]*utxo, error) {
+func findMatchingUTXOs(db dbm.DB, src source) ([]*utxo, error) {
 
        var (
                utxos       []*utxo
@@ -436,7 +419,7 @@ func findMatchingUTXOs(ctx context.Context, db dbm.DB, src source) ([]*utxo, err
        return utxos, nil
 }
 
-func findSpecificUTXO(ctx context.Context, db dbm.DB, outHash bc.Hash) (*utxo, error) {
+func findSpecificUTXO(db dbm.DB, outHash bc.Hash) (*utxo, error) {
        u := new(utxo)
        accountUTXO := new(UTXO)
 
index dd38f1d..181cf76 100755 (executable)
@@ -61,7 +61,6 @@ type Asset struct {
        Tags              map[string]interface{}
        RawDefinitionByte []byte
        DefinitionMap     map[string]interface{}
-       BlockHeight       uint64
 }
 
 func (asset *Asset) Definition() (map[string]interface{}, error) {
index f0ad597..0b9f9ad 100755 (executable)
@@ -3,13 +3,9 @@ package asset
 import (
        "encoding/json"
 
-       log "github.com/sirupsen/logrus"
-
        "github.com/bytom/blockchain/query"
        "github.com/bytom/blockchain/signers"
        chainjson "github.com/bytom/encoding/json"
-       "github.com/bytom/protocol/bc"
-       "github.com/bytom/protocol/bc/legacy"
        "github.com/bytom/protocol/vm/vmutil"
 )
 
@@ -70,61 +66,3 @@ func Annotated(a *Asset) (*query.AnnotatedAsset, error) {
        }
        return aa, nil
 }
-
-// IndexAssets is run on every block and indexes all non-local assets.
-func (reg *Registry) IndexAssets(b *legacy.Block) {
-
-       var err error
-       asset := Asset{}
-       rawSaveAsset := make([]byte, 0)
-       seen := make(map[bc.AssetID]bool)
-       storeBatch := reg.db.NewBatch()
-
-       for _, tx := range b.Transactions {
-               for _, in := range tx.Inputs {
-                       if !in.IsIssuance() {
-                               continue
-                       }
-                       assetID := in.AssetID()
-                       if seen[assetID] {
-                               continue
-                       }
-                       inputIssue, ok := in.TypedInput.(*legacy.IssuanceInput)
-                       if !ok {
-                               continue
-                       }
-
-                       seen[assetID] = true
-
-                       if rawAsset := reg.db.Get([]byte(assetID.String())); rawAsset == nil {
-                               asset.RawDefinitionByte = inputIssue.AssetDefinition
-                               asset.AssetID = assetID
-                               asset.VMVersion = inputIssue.VMVersion
-                               asset.IssuanceProgram = in.IssuanceProgram()
-                               asset.BlockHeight = b.Height
-                               asset.InitialBlockHash = reg.initialBlockHash
-                       } else {
-                               if err = json.Unmarshal(rawAsset, &asset); err != nil {
-                                       log.WithField("AssetID", assetID.String()).Warn("failed unmarshal saved asset")
-                                       continue
-                               }
-                               //update block height which created at
-                               if asset.BlockHeight != 0 {
-                                       continue
-                               }
-                               asset.BlockHeight = b.Height
-                       }
-
-                       rawSaveAsset, err = json.Marshal(&asset)
-                       if err != nil {
-                               log.WithField("AssetID", assetID.String()).Warn("failed marshal to save asset")
-                               continue
-                       }
-
-                       storeBatch.Set([]byte(assetID.String()), rawSaveAsset)
-
-               }
-       }
-
-       storeBatch.Write()
-}
index c110d24..8d0e503 100755 (executable)
@@ -15,7 +15,6 @@ import (
        "github.com/bytom/blockchain/pseudohsm"
        "github.com/bytom/blockchain/txbuilder"
        "github.com/bytom/blockchain/txdb"
-       w "github.com/bytom/blockchain/wallet"
        cfg "github.com/bytom/config"
        "github.com/bytom/crypto/ed25519/chainkd"
        "github.com/bytom/protocol"
@@ -57,7 +56,7 @@ func TestHSM(t *testing.T) {
        assetsDB := dbm.NewDB("asset", config.DBBackend, dir)
        walletDB := dbm.NewDB("wallet", config.DBBackend, config.DBDir())
 
-       accounts = account.NewManager(accountsDB, walletDB, w.GetWalletHeight, chain)
+       accounts = account.NewManager(accountsDB, walletDB, chain)
        assets = asset.NewRegistry(assetsDB, chain)
 
        hsm, err := pseudohsm.New(dirPath)
index 625b717..5cca587 100755 (executable)
@@ -14,7 +14,7 @@ import (
        "github.com/bytom/protocol/bc/legacy"
 )
 
-var walletkey = []byte("walletInfo")
+var walletKey = []byte("walletInfo")
 
 //StatusInfo is base valid block info to handle orphan block rollback
 type StatusInfo struct {
@@ -31,17 +31,14 @@ type Wallet struct {
        StatusInfo
 }
 
-//GlobalWallet for sourceReserve heightFn
-var GlobalWallet Wallet
-
-//InitWallet return a new wallet instance
-func InitWallet(walletDB db.DB, accounts *account.Manager, assets *asset.Registry) *Wallet {
-       GlobalWallet.DB = walletDB
-       GlobalWallet.accounts = accounts
-       GlobalWallet.assets = assets
-       GlobalWallet.Ind = query.NewIndexer(walletDB)
-
-       w := &GlobalWallet
+//NewWallet return a new wallet instance
+func NewWallet(walletDB db.DB, accounts *account.Manager, assets *asset.Registry) *Wallet {
+       w := &Wallet{
+               DB:       walletDB,
+               accounts: accounts,
+               assets:   assets,
+               Ind:      query.NewIndexer(walletDB),
+       }
        walletInfo, err := w.GetWalletInfo()
        if err != nil {
                log.WithField("warn", err).Warn("get wallet info")
@@ -51,18 +48,13 @@ func InitWallet(walletDB db.DB, accounts *account.Manager, assets *asset.Registr
        return w
 }
 
-//GetWalletHeight return wallet on current height
-func GetWalletHeight() uint64 {
-       return GlobalWallet.Height
-}
-
 //GetWalletInfo return stored wallet info and nil,if error,
 //return initial wallet info and err
 func (w *Wallet) GetWalletInfo() (StatusInfo, error) {
        var info StatusInfo
        var rawWallet []byte
 
-       if rawWallet = w.DB.Get(walletkey); rawWallet == nil {
+       if rawWallet = w.DB.Get(walletKey); rawWallet == nil {
                return info, nil
        }
 
@@ -118,7 +110,6 @@ LOOP:
                w.Height = block.Height
                w.Hash = block.Hash()
 
-               w.assets.IndexAssets(block)
                w.accounts.BuildAccountUTXOs(&storeBatch, block)
 
                //update wallet info and commit batch write
@@ -143,7 +134,7 @@ func (w *Wallet) commitWalletInfo(batch *db.Batch) {
                return
        }
        //update wallet to db
-       (*batch).Set(walletkey, rawWallet)
+       (*batch).Set(walletKey, rawWallet)
        //commit to db
        (*batch).Write()
 }
index 887fa07..acf1d97 100755 (executable)
@@ -203,10 +203,10 @@ func NewNode(config *cfg.Config) *Node {
                assetsDB := dbm.NewDB("asset", config.DBBackend, config.DBDir())
                walletDB := dbm.NewDB("wallet", config.DBBackend, config.DBDir())
 
-               accounts = account.NewManager(accountsDB, walletDB, w.GetWalletHeight, chain)
+               accounts = account.NewManager(accountsDB, walletDB, chain)
                assets = asset.NewRegistry(assetsDB, chain)
 
-               wallet = w.InitWallet(walletDB, accounts, assets)
+               wallet = w.NewWallet(walletDB, accounts, assets)
                wallet.Ind.RegisterAnnotator(accounts.AnnotateTxs)
                wallet.Ind.RegisterAnnotator(assets.AnnotateTxs)