OSDN Git Service

edit the code
authorpaladz <453256728@qq.com>
Wed, 18 Apr 2018 15:15:22 +0000 (23:15 +0800)
committerpaladz <453256728@qq.com>
Wed, 18 Apr 2018 15:15:22 +0000 (23:15 +0800)
account/accounts.go
account/image.go
api/query.go
api/wallet.go
asset/asset.go
asset/image.go
blockchain/pseudohsm/image.go
common/bytes.go
wallet/wallet.go

index 3e4f799..38922ae 100644 (file)
@@ -3,7 +3,6 @@ package account
 
 import (
        "context"
-       "encoding/binary"
        "encoding/json"
        "strings"
        "sync"
@@ -28,7 +27,6 @@ import (
 const (
        maxAccountCache     = 1000
        aliasPrefix         = "ALI:"
-       accountPrefix       = "ACC:"
        accountCPPrefix     = "ACP:"
        contractIndexPrefix = "ACPI:"
 )
@@ -36,6 +34,7 @@ const (
 var (
        miningAddressKey = []byte("miningAddress")
        accountIndexKey  = []byte("accountIndex")
+       accountPrefix    = []byte("ACC:")
 )
 
 // pre-define errors for supporting bytom errorFormatter
@@ -51,7 +50,7 @@ func aliasKey(name string) []byte {
 
 //Key account store prefix
 func Key(name string) []byte {
-       return []byte(accountPrefix + name)
+       return append(accountPrefix, []byte(name)...)
 }
 
 //CPKey account control promgram store prefix
@@ -63,17 +62,6 @@ func contractIndexKey(accountID string) []byte {
        return append([]byte(contractIndexPrefix), []byte(accountID)...)
 }
 
-func convertUnit64ToBytes(nextIndex uint64) []byte {
-       buf := make([]byte, 8)
-       binary.PutUvarint(buf, nextIndex)
-       return buf
-}
-
-func convertBytesToUint64(rawIndex []byte) uint64 {
-       result, _ := binary.Uvarint(rawIndex)
-       return result
-}
-
 // NewManager creates a new account manager
 func NewManager(walletDB dbm.DB, chain *protocol.Chain) *Manager {
        return &Manager{
@@ -133,10 +121,10 @@ func (m *Manager) getNextAccountIndex() uint64 {
 
        var nextIndex uint64 = 1
        if rawIndexBytes := m.db.Get(accountIndexKey); rawIndexBytes != nil {
-               nextIndex = convertBytesToUint64(rawIndexBytes) + 1
+               nextIndex = common.BytesToUnit64(rawIndexBytes) + 1
        }
 
-       m.db.Set(accountIndexKey, convertUnit64ToBytes(nextIndex))
+       m.db.Set(accountIndexKey, common.Unit64ToBytes(nextIndex))
        return nextIndex
 }
 
@@ -144,12 +132,12 @@ func (m *Manager) getNextContractIndex(accountID string) uint64 {
        m.accIndexMu.Lock()
        defer m.accIndexMu.Unlock()
 
-       var nextIndex uint64 = 1
+       nextIndex := uint64(1)
        if rawIndexBytes := m.db.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
-               nextIndex = convertBytesToUint64(rawIndexBytes) + 1
+               nextIndex = common.BytesToUnit64(rawIndexBytes) + 1
        }
 
-       m.db.Set(contractIndexKey(accountID), convertUnit64ToBytes(nextIndex))
+       m.db.Set(contractIndexKey(accountID), common.Unit64ToBytes(nextIndex))
        return nextIndex
 }
 
@@ -448,9 +436,9 @@ func (m *Manager) DeleteAccount(aliasOrId string) (err error) {
 }
 
 // ListAccounts will return the accounts in the db
-func (m *Manager) ListAccounts(id string) ([]*Account, error) {
+func (m *Manager) ListAccounts() ([]*Account, error) {
        accounts := []*Account{}
-       accountIter := m.db.IteratorPrefix([]byte(accountPrefix + id))
+       accountIter := m.db.IteratorPrefix(accountPrefix)
        defer accountIter.Release()
 
        for accountIter.Next() {
index 85c3ae7..1d05f40 100644 (file)
@@ -3,66 +3,74 @@ package account
 
 import (
        "encoding/json"
+
+       "github.com/bytom/common"
 )
 
-type AccountSlice struct {
-       Account       *Account
-       ContractIndex uint64
+// ImageSlice record info of single account
+type ImageSlice struct {
+       Account       *Account `json:"account"`
+       ContractIndex uint64   `json:"contract_index"`
 }
 
-type AccountImage struct {
-       AccountSlice []*AccountSlice
-       AccountIndex uint64
+// Image is the struct for hold export account data
+type Image struct {
+       Slice        []*ImageSlice `json:"slices"`
+       AccountIndex uint64        `json:"account_index"`
 }
 
-func (m *Manager) Backup() (*AccountImage, error) {
-       accountSlices := []*AccountSlice{}
-       accountIter := m.db.IteratorPrefix([]byte(accountPrefix))
-       defer accountIter.Release()
+// Backup export all the account info into image
+func (m *Manager) Backup() (*Image, error) {
+       image := &Image{
+               Slice:        []*ImageSlice{},
+               AccountIndex: m.getNextAccountIndex(),
+       }
 
+       accountIter := m.db.IteratorPrefix(accountPrefix)
+       defer accountIter.Release()
        for accountIter.Next() {
                a := &Account{}
                if err := json.Unmarshal(accountIter.Value(), a); err != nil {
                        return nil, err
                }
 
-               accountSlice := &AccountSlice{
+               image.Slice = append(image.Slice, &ImageSlice{
                        Account:       a,
                        ContractIndex: m.getNextContractIndex(a.ID),
-               }
-               accountSlices = append(accountSlices, accountSlice)
+               })
        }
-
-       accountImage := &AccountImage{
-               AccountSlice: accountSlices,
-               AccountIndex: m.getNextAccountIndex(),
-       }
-       return accountImage, nil
+       return image, nil
 }
 
-func (m *Manager) Restore(image *AccountImage) error {
-       if localIndex := m.getNextAccountIndex(); localIndex > image.AccountIndex {
-               image.AccountIndex = localIndex
-       }
-
+// Restore import the accountImages into account manage
+func (m *Manager) Restore(image *Image) error {
        storeBatch := m.db.NewBatch()
-       for _, accountSlice := range image.AccountSlice {
-               rawAccount, err := json.Marshal(accountSlice.Account)
-               if err != nil {
-                       return ErrMarshalAccount
+       for _, slice := range image.Slice {
+               if existed := m.db.Get(aliasKey(slice.Account.Alias)); existed != nil {
+                       return ErrDuplicateAlias
                }
 
-               if existed := m.db.Get(aliasKey(accountSlice.Account.Alias)); existed != nil {
-                       return ErrDuplicateAlias
+               rawAccount, err := json.Marshal(slice.Account)
+               if err != nil {
+                       return ErrMarshalAccount
                }
 
-               accountID := Key(accountSlice.Account.ID)
-               storeBatch.Set(accountID, rawAccount)
-               storeBatch.Set(aliasKey(accountSlice.Account.Alias), accountID)
-               storeBatch.Set(contractIndexKey(accountSlice.Account.ID), convertUnit64ToBytes(accountSlice.ContractIndex))
+               storeBatch.Set(Key(slice.Account.ID), rawAccount)
+               storeBatch.Set(aliasKey(slice.Account.Alias), []byte(slice.Account.ID))
+               storeBatch.Set(contractIndexKey(slice.Account.ID), common.Unit64ToBytes(slice.ContractIndex))
        }
 
-       storeBatch.Set(accountIndexKey, convertUnit64ToBytes(image.AccountIndex))
+       if localIndex := m.getNextAccountIndex(); localIndex < image.AccountIndex {
+               storeBatch.Set(accountIndexKey, common.Unit64ToBytes(image.AccountIndex))
+       }
        storeBatch.Write()
+
+       for _, slice := range image.Slice {
+               for i := uint64(1); i < slice.ContractIndex; i++ {
+                       if _, err := m.createAddress(nil, slice.Account, false); err != nil {
+                               return err
+                       }
+               }
+       }
        return nil
 }
index 5fd9411..ac3c37d 100644 (file)
@@ -14,10 +14,8 @@ import (
 )
 
 // POST /list-accounts
-func (a *API) listAccounts(ctx context.Context, filter struct {
-       ID string `json:"id"`
-}) Response {
-       accounts, err := a.wallet.AccountMgr.ListAccounts(filter.ID)
+func (a *API) listAccounts(ctx context.Context) Response {
+       accounts, err := a.wallet.AccountMgr.ListAccounts()
        if err != nil {
                log.Errorf("listAccounts: %v", err)
                return NewErrorResponse(err)
index dabdb78..78f3bb6 100644 (file)
@@ -14,37 +14,39 @@ func (a *API) walletError() Response {
        return NewErrorResponse(errors.New("wallet not found, please check that the wallet is open"))
 }
 
+// WalletImage hold the ziped wallet data
 type WalletImage struct {
-       AccountImage *account.AccountImage
-       AssetImage   *asset.AssetImage
-       KeyImages    []*pseudohsm.KeyImage
+       AccountImage *account.Image        `json:"account_image"`
+       AssetImage   *asset.Image          `json:"asset_image"`
+       KeyImages    []*pseudohsm.KeyImage `json:"key_images"`
 }
 
 func (a *API) restoreWalletImage(ctx context.Context, image WalletImage) Response {
        if err := a.wallet.Hsm.Restore(image.KeyImages); err != nil {
-               return NewErrorResponse(err)
+               return NewErrorResponse(errors.Wrap(err, "restore key images"))
        }
        if err := a.wallet.AssetReg.Restore(image.AssetImage); err != nil {
-               return NewErrorResponse(err)
+               return NewErrorResponse(errors.Wrap(err, "restore asset image"))
        }
        if err := a.wallet.AccountMgr.Restore(image.AccountImage); err != nil {
-               return NewErrorResponse(err)
+               return NewErrorResponse(errors.Wrap(err, "restore account image"))
        }
+       a.wallet.RescanBlocks()
        return NewSuccessResponse(nil)
 }
 
 func (a *API) backupWalletImage() Response {
        keyImages, err := a.wallet.Hsm.Backup()
        if err != nil {
-               return NewErrorResponse(err)
+               return NewErrorResponse(errors.Wrap(err, "backup key images"))
        }
        assetImage, err := a.wallet.AssetReg.Backup()
        if err != nil {
-               return NewErrorResponse(err)
+               return NewErrorResponse(errors.Wrap(err, "backup asset image"))
        }
        accountImage, err := a.wallet.AccountMgr.Backup()
        if err != nil {
-               return NewErrorResponse(err)
+               return NewErrorResponse(errors.Wrap(err, "backup account image"))
        }
 
        image := &WalletImage{
index 1344db0..1696642 100644 (file)
@@ -2,7 +2,6 @@ package asset
 
 import (
        "context"
-       "encoding/binary"
        "encoding/json"
        "strings"
        "sync"
@@ -12,6 +11,7 @@ import (
        "golang.org/x/crypto/sha3"
 
        "github.com/bytom/blockchain/signers"
+       "github.com/bytom/common"
        "github.com/bytom/consensus"
        "github.com/bytom/crypto/ed25519"
        "github.com/bytom/crypto/ed25519/chainkd"
@@ -27,14 +27,16 @@ var DefaultNativeAsset *Asset
 
 const (
        maxAssetCache = 1000
-       assetPrefix   = "ASS:"
        //AliasPrefix is asset alias prefix
        AliasPrefix = "ALS:"
        //ExternalAssetPrefix is external definition assets prefix
        ExternalAssetPrefix = "EXA"
 )
 
-var assetIndexKey = []byte("ASSETINDEX")
+var (
+       assetIndexKey = []byte("assetIndex")
+       assetPrefix   = []byte("ASS:")
+)
 
 func initNativeAsset() {
        signer := &signers.Signer{Type: "internal"}
@@ -58,8 +60,7 @@ func AliasKey(name string) []byte {
 
 //Key asset store prefix
 func Key(id *bc.AssetID) []byte {
-       name := id.String()
-       return []byte(assetPrefix + name)
+       return append(assetPrefix, id.Bytes()...)
 }
 
 //CalcExtAssetKey return store external assets key
@@ -113,24 +114,17 @@ type Asset struct {
        DefinitionMap     map[string]interface{} `json:"definition"`
 }
 
-func (reg *Registry) getNextAssetIndex() (uint64, error) {
+func (reg *Registry) getNextAssetIndex() uint64 {
        reg.assetIndexMu.Lock()
        defer reg.assetIndexMu.Unlock()
 
-       var nextIndex uint64 = 1
-
+       nextIndex := uint64(1)
        if rawIndex := reg.db.Get(assetIndexKey); rawIndex != nil {
-               nextIndex = binary.LittleEndian.Uint64(rawIndex) + 1
+               nextIndex = common.BytesToUnit64(rawIndex) + 1
        }
 
-       reg.saveNextAssetIndex(nextIndex)
-       return nextIndex, nil
-}
-
-func (reg *Registry) saveNextAssetIndex(nextIndex uint64) {
-       buf := make([]byte, 8)
-       binary.LittleEndian.PutUint64(buf, nextIndex)
-       reg.db.Set(assetIndexKey, buf)
+       reg.db.Set(assetIndexKey, common.Unit64ToBytes(nextIndex))
+       return nextIndex
 }
 
 // Define defines a new Asset.
@@ -148,11 +142,7 @@ func (reg *Registry) Define(xpubs []chainkd.XPub, quorum int, definition map[str
                return nil, ErrDuplicateAlias
        }
 
-       nextAssetIndex, err := reg.getNextAssetIndex()
-       if err != nil {
-               return nil, errors.Wrap(err, "get asset index error")
-       }
-
+       nextAssetIndex := reg.getNextAssetIndex()
        assetSigner, err := signers.Create("asset", xpubs, quorum, nextAssetIndex)
        if err != nil {
                return nil, err
@@ -285,7 +275,7 @@ func (reg *Registry) GetAliasByID(id string) string {
 // ListAssets returns the accounts in the db
 func (reg *Registry) ListAssets(id string) ([]*Asset, error) {
        assets := []*Asset{DefaultNativeAsset}
-       assetIter := reg.db.IteratorPrefix([]byte(assetPrefix + id))
+       assetIter := reg.db.IteratorPrefix(assetPrefix)
        defer assetIter.Release()
 
        for assetIter.Next() {
index 323f873..a6c141e 100644 (file)
@@ -2,52 +2,49 @@ package asset
 
 import (
        "encoding/json"
+
+       log "github.com/sirupsen/logrus"
+
+       "github.com/bytom/common"
 )
 
-type AssetImage struct {
-       Assets     []*Asset
-       AssetIndex uint64
+// Image is the struct for hold export asset data
+type Image struct {
+       Assets     []*Asset `json:"assets"`
+       AssetIndex uint64   `json:"asset_index"`
 }
 
-func (reg *Registry) Backup() (*AssetImage, error) {
-       assetIndex, err := reg.getNextAssetIndex()
-       if err != nil {
-               return nil, err
+// Backup export all the asset info into image
+func (reg *Registry) Backup() (*Image, error) {
+       assetImage := &Image{
+               AssetIndex: reg.getNextAssetIndex(),
+               Assets:     []*Asset{},
        }
 
-       assets := []*Asset{}
        assetIter := reg.db.IteratorPrefix([]byte(assetPrefix))
        defer assetIter.Release()
-
        for assetIter.Next() {
                asset := &Asset{}
                if err := json.Unmarshal(assetIter.Value(), asset); err != nil {
                        return nil, err
                }
-               assets = append(assets, asset)
+               assetImage.Assets = append(assetImage.Assets, asset)
        }
 
-       assetImage := &AssetImage{
-               AssetIndex: assetIndex,
-               Assets:     assets,
-       }
        return assetImage, nil
 }
 
-func (reg *Registry) Restore(image *AssetImage) error {
-       localIndex, err := reg.getNextAssetIndex()
-       if err != nil {
-               return err
-       }
-
-       if localIndex > image.AssetIndex {
-               image.AssetIndex = localIndex
-       }
-
+// Restore load the image data into asset manage
+func (reg *Registry) Restore(image *Image) error {
        storeBatch := reg.db.NewBatch()
        for _, asset := range image.Assets {
-               if existed := reg.db.Get(AliasKey(*asset.Alias)); existed != nil {
-                       return ErrDuplicateAlias
+               if localAssetID := reg.db.Get(AliasKey(*asset.Alias)); localAssetID != nil {
+                       if string(localAssetID) != asset.AssetID.String() {
+                               return ErrDuplicateAlias
+                       }
+
+                       log.WithFields(log.Fields{"alias": asset.Alias, "id": asset.AssetID}).Warning("skip restore asset due to already existed")
+                       continue
                }
 
                rawAsset, err := json.Marshal(asset)
@@ -55,10 +52,13 @@ func (reg *Registry) Restore(image *AssetImage) error {
                        return err
                }
 
-               storeBatch.Set(AliasKey(*asset.Alias), []byte(asset.AssetID.String()))
+               storeBatch.Set(AliasKey(*asset.Alias), asset.AssetID.Bytes())
                storeBatch.Set(Key(&asset.AssetID), rawAsset)
        }
+
+       if localIndex := reg.getNextAssetIndex(); localIndex < image.AssetIndex {
+               storeBatch.Set(assetIndexKey, common.Unit64ToBytes(image.AssetIndex))
+       }
        storeBatch.Write()
-       reg.saveNextAssetIndex(image.AssetIndex)
        return nil
 }
index 4025f92..4fecb34 100644 (file)
@@ -6,11 +6,13 @@ import (
        "path/filepath"
 )
 
+// KeyImage is the struct for hold export key data
 type KeyImage struct {
        XPub XPub   `json:"xpub"`
        XKey []byte `json:"xkey"`
 }
 
+// Backup export all the HSM keys into array
 func (h *HSM) Backup() ([]*KeyImage, error) {
        images := []*KeyImage{}
        xpubs := h.cache.keys()
@@ -25,6 +27,7 @@ func (h *HSM) Backup() ([]*KeyImage, error) {
        return images, nil
 }
 
+// Restore import the keyImages into HSM
 func (h *HSM) Restore(images []*KeyImage) error {
        for _, image := range images {
                if ok := h.cache.hasAlias(image.XPub.Alias); ok {
index 12376eb..170cf5f 100644 (file)
@@ -265,3 +265,13 @@ func ByteSliceToInterface(slice [][]byte) (ret []interface{}) {
 
        return
 }
+
+func Unit64ToBytes(n uint64) []byte {
+       buf := make([]byte, 8)
+       binary.LittleEndian.PutUint64(buf, n)
+       return buf
+}
+
+func BytesToUnit64(b []byte) uint64 {
+       return binary.LittleEndian.Uint64(b)
+}
index a5143c3..f2d1ad7 100644 (file)
@@ -2,6 +2,7 @@ package wallet
 
 import (
        "encoding/json"
+
        log "github.com/sirupsen/logrus"
        "github.com/tendermint/tmlibs/db"
 
@@ -23,30 +24,32 @@ var walletKey = []byte("walletInfo")
 
 //StatusInfo is base valid block info to handle orphan block rollback
 type StatusInfo struct {
-       WorkHeight       uint64
-       WorkHash         bc.Hash
-       BestHeight       uint64
-       BestHash         bc.Hash
+       WorkHeight uint64
+       WorkHash   bc.Hash
+       BestHeight uint64
+       BestHash   bc.Hash
 }
 
 //Wallet is related to storing account unspent outputs
 type Wallet struct {
-       DB                  db.DB
-       status              StatusInfo
-       AccountMgr          *account.Manager
-       AssetReg            *asset.Registry
-       Hsm                 *pseudohsm.HSM
-       chain               *protocol.Chain
+       DB         db.DB
+       status     StatusInfo
+       AccountMgr *account.Manager
+       AssetReg   *asset.Registry
+       Hsm        *pseudohsm.HSM
+       chain      *protocol.Chain
+       rescanCh   chan struct{}
 }
 
 //NewWallet return a new wallet instance
 func NewWallet(walletDB db.DB, account *account.Manager, asset *asset.Registry, hsm *pseudohsm.HSM, chain *protocol.Chain) (*Wallet, error) {
        w := &Wallet{
-               DB:                  walletDB,
-               AccountMgr:          account,
-               AssetReg:            asset,
-               chain:               chain,
-               Hsm:                 hsm,
+               DB:         walletDB,
+               AccountMgr: account,
+               AssetReg:   asset,
+               chain:      chain,
+               Hsm:        hsm,
+               rescanCh:   make(chan struct{}, 1),
        }
 
        if err := w.loadWalletInfo(); err != nil {
@@ -136,6 +139,7 @@ func (w *Wallet) DetachBlock(block *types.Block) error {
 //WalletUpdate process every valid block and reverse every invalid block which need to rollback
 func (w *Wallet) walletUpdater() {
        for {
+               w.getRescanNotification()
                for !w.chain.InMainChain(w.status.BestHash) {
                        block, err := w.chain.GetBlockByHash(&w.status.BestHash)
                        if err != nil {
@@ -162,6 +166,24 @@ func (w *Wallet) walletUpdater() {
        }
 }
 
+func (w *Wallet) RescanBlocks() {
+       select {
+       case w.rescanCh <- struct{}{}:
+       default:
+               return
+       }
+}
+
+func (w *Wallet) getRescanNotification() {
+       select {
+       case <-w.rescanCh:
+               w.status.WorkHeight = 0
+               block, _ := w.chain.GetBlockByHeight(w.status.WorkHeight)
+               w.status.WorkHash = block.Hash()
+       default:
+               return
+       }
+}
 
 func (w *Wallet) createProgram(account *account.Account, XPub *pseudohsm.XPub, index uint64) error {
        for i := uint64(0); i < index; i++ {