OSDN Git Service

Add external asset ailas and definition (#278)
authoricodezjb <icodezjb@163.com>
Fri, 19 Jan 2018 01:53:05 +0000 (09:53 +0800)
committerPaladz <yzhu101@uottawa.ca>
Fri, 19 Jan 2018 01:53:05 +0000 (09:53 +0800)
* Save external asset alias and definition

(cherry picked from commit 0c59d87)

* Add btm definition

(cherry picked from commit 6c8d2b5)

* rename external asset alias

* use getNativeAsset

* skip save local asset definition

* index external asset definition

* Add update-asset-alias cmd

* Use assetID as asset alias if no alias in definition

* Add update-asset-alias ErrNullAlias

* Add native_asset_definition in genesis.json

* Reverse native_asset_definition

* Unused SerializeAssetDef

* use Registry.FindByID

* use CalcExtAssetKey

* Only remove aliasCache

* Add cache newAlias to assetID

* Resolve code conflict

17 files changed:
blockchain/account/accounts.go
blockchain/asset/annotate.go
blockchain/asset/asset.go
blockchain/asset/asset_test.go
blockchain/asset/builder.go
blockchain/assets.go
blockchain/query/annotated.go
blockchain/request.go
blockchain/rpc_reactor.go
blockchain/txfeed/txfeed.go
blockchain/wallet.go
blockchain/wallet/annotated.go
blockchain/wallet/indexer.go
cmd/bytomcli/commands/asset.go
cmd/bytomcli/commands/bytomcli.go
cmd/bytomd/commands/run_node.go
consensus/general.go

index 37e63f8..6d27c0e 100755 (executable)
@@ -407,10 +407,15 @@ func (m *Manager) DeleteAccount(in struct {
        }
 
        storeBatch := m.db.NewBatch()
+
+       m.cacheMu.Lock()
        m.aliasCache.Remove(account.Alias)
+       m.cacheMu.Unlock()
+
        storeBatch.Delete(aliasKey(account.Alias))
        storeBatch.Delete(Key(account.ID))
        storeBatch.Write()
+
        return nil
 }
 
index eb49e0f..f5aa5fe 100755 (executable)
@@ -20,10 +20,10 @@ func Annotated(a *Asset) (*query.AnnotatedAsset, error) {
        jsonTags := json.RawMessage(`{}`)
        jsonDefinition := json.RawMessage(`{}`)
 
-       // a.RawDefinition is the asset definition as it appears on the
+       // a.RawDefinitionByte is the asset definition as it appears on the
        // blockchain, so it's untrusted and may not be valid json.
-       if isValidJSON(a.RawDefinition()) {
-               jsonDefinition = json.RawMessage(a.RawDefinition())
+       if isValidJSON(a.RawDefinitionByte) {
+               jsonDefinition = json.RawMessage(a.RawDefinitionByte)
        }
 
        if a.Tags != nil {
index 121d0ae..5ad2e84 100755 (executable)
@@ -12,6 +12,7 @@ import (
        "golang.org/x/crypto/sha3"
 
        "github.com/bytom/blockchain/signers"
+       cfg "github.com/bytom/config"
        "github.com/bytom/consensus"
        "github.com/bytom/crypto/ed25519"
        "github.com/bytom/crypto/ed25519/chainkd"
@@ -22,15 +23,41 @@ import (
        "github.com/bytom/protocol/vm/vmutil"
 )
 
+func init() {
+       DefaultNativeAsset = generateNativeAsset()
+}
+
+var DefaultNativeAsset *Asset
+
 const (
        maxAssetCache = 1000
        assetPrefix   = "ASS:"
-       aliasPrefix   = "ALS:"
+       //AliasPrefix is asset alias prefix
+       AliasPrefix = "ALS:"
+       //ExternalAssetPrefix is external definition assets prefix
+       ExternalAssetPrefix = "EXA"
        indexPrefix   = "ASSIDX:"
 )
 
-func aliasKey(name string) []byte {
-       return []byte(aliasPrefix + name)
+func generateNativeAsset() *Asset {
+       genesisBlock := cfg.GenerateGenesisBlock()
+       signer := &signers.Signer{Type: "internal"}
+       alias := consensus.BTMAlias
+
+       definitionBytes, _ := serializeAssetDef(consensus.BTMDefinitionMap)
+
+       return &Asset{
+               Signer:            signer,
+               AssetID:           *consensus.BTMAssetID,
+               Alias:             &alias,
+               VMVersion:         1,
+               DefinitionMap:     consensus.BTMDefinitionMap,
+               RawDefinitionByte: definitionBytes,
+               InitialBlockHash:  genesisBlock.Hash()}
+}
+
+func AliasKey(name string) []byte {
+       return []byte(AliasPrefix + name)
 }
 
 //Key asset store prefix
@@ -43,6 +70,12 @@ func indexKey(xpub chainkd.XPub) []byte {
        return []byte(indexPrefix + xpub.String())
 }
 
+//CalcExtAssetKey return store external assets key
+func CalcExtAssetKey(id *bc.AssetID) []byte {
+       name := id.String()
+       return []byte(ExternalAssetPrefix + name)
+}
+
 // pre-define errors for supporting bytom errorFormatter
 var (
        ErrDuplicateAlias = errors.New("duplicate asset alias")
@@ -51,6 +84,7 @@ var (
        ErrMarshalAsset   = errors.New("failed marshal asset")
        ErrFindAsset      = errors.New("fail to find asset")
        ErrInternalAsset  = errors.New("btm has been defined as the internal asset")
+       ErrNullAlias      = errors.New("null asset alias")
 )
 
 //NewRegistry create new registry
@@ -89,15 +123,10 @@ type Asset struct {
        IssuanceProgram   chainjson.HexBytes     `json:"issue_program"`
        InitialBlockHash  bc.Hash                `json:"init_blockhash"`
        Tags              map[string]interface{} `json:"tags"`
-       RawDefinitionByte []byte                 `json:"raw_definition_byte"`
+       RawDefinitionByte chainjson.HexBytes     `json:"raw_definition_byte"`
        DefinitionMap     map[string]interface{} `json:"definition"`
 }
 
-//RawDefinition return asset in the raw format
-func (asset *Asset) RawDefinition() []byte {
-       return asset.RawDefinitionByte
-}
-
 func (reg *Registry) getNextAssetIndex(xpubs []chainkd.XPub) (*uint64, error) {
        reg.assetIndexMu.Lock()
        defer reg.assetIndexMu.Unlock()
@@ -117,11 +146,11 @@ func (reg *Registry) getNextAssetIndex(xpubs []chainkd.XPub) (*uint64, error) {
 
 // Define defines a new Asset.
 func (reg *Registry) Define(xpubs []chainkd.XPub, quorum int, definition map[string]interface{}, alias string, tags map[string]interface{}) (*Asset, error) {
-       if alias == "btm" {
+       if alias == consensus.BTMAlias {
                return nil, ErrInternalAsset
        }
 
-       if existed := reg.db.Get(aliasKey(alias)); existed != nil {
+       if existed := reg.db.Get(AliasKey(alias)); existed != nil {
                return nil, ErrDuplicateAlias
        }
 
@@ -174,7 +203,7 @@ func (reg *Registry) Define(xpubs []chainkd.XPub, quorum int, definition map[str
        }
 
        storeBatch := reg.db.NewBatch()
-       storeBatch.Set(aliasKey(alias), []byte(asset.AssetID.String()))
+       storeBatch.Set(AliasKey(alias), []byte(asset.AssetID.String()))
        storeBatch.Set(Key(&asset.AssetID), ass)
        storeBatch.Write()
 
@@ -190,7 +219,7 @@ func (reg *Registry) UpdateTags(ctx context.Context, assetInfo string, tags map[
                if err := assetID.UnmarshalText([]byte(assetInfo)); err != nil {
                        return err
                }
-               if asset, err = reg.findByID(ctx, assetID); err != nil {
+               if asset, err = reg.FindByID(ctx, assetID); err != nil {
                        return err
                }
        }
@@ -209,7 +238,7 @@ func (reg *Registry) UpdateTags(ctx context.Context, assetInfo string, tags map[
 }
 
 // findByID retrieves an Asset record along with its signer, given an assetID.
-func (reg *Registry) findByID(ctx context.Context, id *bc.AssetID) (*Asset, error) {
+func (reg *Registry) FindByID(ctx context.Context, id *bc.AssetID) (*Asset, error) {
        reg.cacheMu.Lock()
        cached, ok := reg.cache.Get(id.String())
        reg.cacheMu.Unlock()
@@ -233,6 +262,15 @@ func (reg *Registry) findByID(ctx context.Context, id *bc.AssetID) (*Asset, erro
        return asset, nil
 }
 
+//GetIDByAlias return AssetID string and nil by asset alias,if err ,return "" and err
+func (reg *Registry) GetIDByAlias(alias string) (string, error) {
+       rawID := reg.db.Get(AliasKey(alias))
+       if rawID == nil {
+               return "", ErrFindAsset
+       }
+       return string(rawID), nil
+}
+
 // FindByAlias retrieves an Asset record along with its signer,
 // given an asset alias.
 func (reg *Registry) FindByAlias(ctx context.Context, alias string) (*Asset, error) {
@@ -240,10 +278,10 @@ func (reg *Registry) FindByAlias(ctx context.Context, alias string) (*Asset, err
        cachedID, ok := reg.aliasCache.Get(alias)
        reg.cacheMu.Unlock()
        if ok {
-               return reg.findByID(ctx, cachedID.(*bc.AssetID))
+               return reg.FindByID(ctx, cachedID.(*bc.AssetID))
        }
 
-       rawID := reg.db.Get(aliasKey(alias))
+       rawID := reg.db.Get(AliasKey(alias))
        if rawID == nil {
                return nil, errors.Wrapf(ErrFindAsset, "no such asset, alias: %s", alias)
        }
@@ -256,27 +294,32 @@ func (reg *Registry) FindByAlias(ctx context.Context, alias string) (*Asset, err
        reg.cacheMu.Lock()
        reg.aliasCache.Add(alias, assetID)
        reg.cacheMu.Unlock()
-       return reg.findByID(ctx, assetID)
+       return reg.FindByID(ctx, assetID)
 }
 
+//GetAliasByID return asset alias string by AssetID string
 func (reg *Registry) GetAliasByID(id string) string {
+       //btm
        if id == consensus.BTMAssetID.String() {
-               return "btm"
+               return consensus.BTMAlias
        }
+
        assetID := &bc.AssetID{}
        if err := assetID.UnmarshalText([]byte(id)); err != nil {
                return ""
        }
-       asset, err := reg.findByID(nil, assetID)
+
+       asset, err := reg.FindByID(nil, assetID)
        if err != nil {
                return ""
        }
+
        return *asset.Alias
 }
 
 // ListAssets returns the accounts in the db
 func (reg *Registry) ListAssets(id string) ([]*Asset, error) {
-       assets := []*Asset{}
+       assets := []*Asset{DefaultNativeAsset}
        assetIter := reg.db.IteratorPrefix([]byte(assetPrefix + id))
        defer assetIter.Release()
 
@@ -313,3 +356,43 @@ func multisigIssuanceProgram(pubkeys []ed25519.PublicKey, nrequired int) (progra
        prog, err := builder.Build()
        return prog, 1, err
 }
+
+//UpdateAssetAlias updates oldAlias to newAlias
+func (reg *Registry) UpdateAssetAlias(oldAlias, newAlias string) error {
+       if oldAlias == consensus.BTMAlias || newAlias == consensus.BTMAlias {
+               return ErrInternalAsset
+       }
+
+       if oldAlias == "" || newAlias == "" {
+               return ErrNullAlias
+       }
+
+       if _, err := reg.GetIDByAlias(newAlias); err == nil {
+               return ErrDuplicateAlias
+       }
+
+       findAsset, err := reg.FindByAlias(nil, oldAlias)
+       if err != nil {
+               return err
+       }
+
+       storeBatch := reg.db.NewBatch()
+       findAsset.Alias = &newAlias
+       assetID := &findAsset.AssetID
+       rawAsset, err := json.Marshal(findAsset)
+       if err != nil {
+               return err
+       }
+
+       storeBatch.Set(Key(assetID), rawAsset)
+       storeBatch.Set(AliasKey(newAlias), []byte(assetID.String()))
+       storeBatch.Delete(AliasKey(oldAlias))
+       storeBatch.Write()
+
+       reg.cacheMu.Lock()
+       reg.aliasCache.Add(newAlias, assetID)
+       reg.aliasCache.Remove(oldAlias)
+       reg.cacheMu.Unlock()
+
+       return nil
+}
index cbe89e0..a102124 100644 (file)
@@ -23,7 +23,7 @@ func TestDefineAsset(t *testing.T) {
                testutil.FatalErr(t, err)
        }
 
-       found, err := reg.findByID(ctx, &asset.AssetID)
+       found, err := reg.FindByID(ctx, &asset.AssetID)
        if err != nil {
                t.Errorf("unexpected error %v", err)
        }
@@ -42,7 +42,7 @@ func TestFindAssetByID(t *testing.T) {
                testutil.FatalErr(t, err)
 
        }
-       found, err := reg.findByID(ctx, &asset.AssetID)
+       found, err := reg.FindByID(ctx, &asset.AssetID)
        if err != nil {
                testutil.FatalErr(t, err)
        }
index f49fef1..1511c07 100755 (executable)
@@ -42,7 +42,7 @@ func (a *issueAction) Build(ctx context.Context, builder *txbuilder.TemplateBuil
                return txbuilder.MissingFieldsError("asset_id")
        }
 
-       asset, err := a.assets.findByID(ctx, a.AssetId)
+       asset, err := a.assets.FindByID(ctx, a.AssetId)
        if err != nil {
                return err
        }
@@ -53,7 +53,7 @@ func (a *issueAction) Build(ctx context.Context, builder *txbuilder.TemplateBuil
                return err
        }
 
-       assetDef := asset.RawDefinition()
+       assetDef := asset.RawDefinitionByte
 
        txin := legacy.NewIssuanceInput(nonce[:], a.Amount, a.ReferenceData, asset.InitialBlockHash, asset.IssuanceProgram, nil, assetDef)
 
index 6a1c03a..b36ec46 100644 (file)
@@ -50,3 +50,15 @@ func (bcr *BlockchainReactor) updateAssetTags(ctx context.Context, updateTag str
 
        return resWrapper(nil)
 }
+
+// POST /update-asset-alias
+func (bcr *BlockchainReactor) updateAssetAlias(updateAlias struct {
+       OldAlias string `json:"old_alias"`
+       NewAlias string `json:"new_alias"`
+}) Response {
+       if err := bcr.assets.UpdateAssetAlias(updateAlias.OldAlias, updateAlias.NewAlias); err != nil {
+               return resWrapper(nil, err)
+       }
+
+       return resWrapper(nil)
+}
index a84c8b9..de04f4f 100755 (executable)
@@ -28,14 +28,12 @@ type AnnotatedInput struct {
        AssetID         bc.AssetID         `json:"asset_id"`
        AssetAlias      string             `json:"asset_alias,omitempty"`
        AssetDefinition *json.RawMessage   `json:"asset_definition"`
-       AssetTags       *json.RawMessage   `json:"asset_tags,omitempty"`
        Amount          uint64             `json:"amount"`
        IssuanceProgram chainjson.HexBytes `json:"issuance_program,omitempty"`
        ControlProgram  chainjson.HexBytes `json:"-"`
        SpentOutputID   *bc.Hash           `json:"spent_output_id,omitempty"`
        AccountID       string             `json:"account_id,omitempty"`
        AccountAlias    string             `json:"account_alias,omitempty"`
-       AccountTags     *json.RawMessage   `json:"account_tags,omitempty"`
        ReferenceData   *json.RawMessage   `json:"reference_data"`
        Arbitrary       chainjson.HexBytes `json:"arbitrary,omitempty"`
 }
@@ -49,11 +47,9 @@ type AnnotatedOutput struct {
        AssetID         bc.AssetID         `json:"asset_id"`
        AssetAlias      string             `json:"asset_alias,omitempty"`
        AssetDefinition *json.RawMessage   `json:"asset_definition"`
-       AssetTags       *json.RawMessage   `json:"asset_tags"`
        Amount          uint64             `json:"amount"`
        AccountID       string             `json:"account_id,omitempty"`
        AccountAlias    string             `json:"account_alias,omitempty"`
-       AccountTags     *json.RawMessage   `json:"account_tags,omitempty"`
        ControlProgram  chainjson.HexBytes `json:"control_program"`
        ReferenceData   *json.RawMessage   `json:"reference_data"`
 }
index 4eb90fe..a2d79b0 100644 (file)
@@ -11,7 +11,6 @@ import (
 
 var (
        errBadActionType = errors.New("bad action type")
-       errBadAlias      = errors.New("bad alias")
        errBadAction     = errors.New("bad action object")
 )
 
@@ -27,14 +26,14 @@ func (bcr *BlockchainReactor) filterAliases(ctx context.Context, br *BuildReques
                alias, _ := m["asset_alias"].(string)
                if id == "" && alias != "" {
                        switch alias {
-                       case "btm":
+                       case consensus.BTMAlias:
                                m["asset_id"] = consensus.BTMAssetID.String()
                        default:
-                               asset, err := bcr.assets.FindByAlias(ctx, alias)
+                               id, err := bcr.assets.GetIDByAlias(alias)
                                if err != nil {
                                        return errors.WithDetailf(err, "invalid asset alias %s on action %d", alias, i)
                                }
-                               m["asset_id"] = asset.AssetID.String()
+                               m["asset_id"] = id
                        }
                }
 
index 6626d18..5b0439e 100644 (file)
@@ -59,6 +59,7 @@ func (bcr *BlockchainReactor) BuildHandler() {
                m.Handle("/delete-account", jsonHandler(bcr.deleteAccount))
 
                m.Handle("/create-asset", jsonHandler(bcr.createAsset))
+               m.Handle("/update-asset-alias", jsonHandler(bcr.updateAssetAlias))
                m.Handle("/update-asset-tags", jsonHandler(bcr.updateAssetTags))
                m.Handle("/list-assets", jsonHandler(bcr.listAssets))
 
index fa319be..6603da8 100755 (executable)
@@ -343,7 +343,6 @@ func buildAnnotatedInput(tx *legacy.Tx, i uint32) *query.AnnotatedInput {
                AssetID:         orig.AssetID(),
                Amount:          orig.Amount(),
                AssetDefinition: &emptyJSONObject,
-               AssetTags:       &emptyJSONObject,
                ReferenceData:   &emptyJSONObject,
        }
 
@@ -370,7 +369,6 @@ func buildAnnotatedOutput(tx *legacy.Tx, idx int) *query.AnnotatedOutput {
                Position:        idx,
                AssetID:         *orig.AssetId,
                AssetDefinition: &emptyJSONObject,
-               AssetTags:       &emptyJSONObject,
                Amount:          orig.Amount,
                ControlProgram:  orig.ControlProgram,
                ReferenceData:   &emptyJSONObject,
index 442d279..1dc2fda 100644 (file)
@@ -3,19 +3,19 @@ package blockchain
 import (
        "context"
 
+       "bytes"
        "github.com/bytom/crypto/ed25519/chainkd"
-       "github.com/tendermint/go-wire/data/base58"
-       "chain/errors"
        "github.com/bytom/crypto/sha3pool"
-       "bytes"
+       "github.com/bytom/errors"
+       "github.com/tendermint/go-wire/data/base58"
 )
 
 type KeyImportParams struct {
-       KeyAlias     string       `json:"alias"`
-       Password     string       `json:"password"`
-       XPrv         string       `json:"xprv"`
-       Index        uint64       `json:"index"`
-       AccountAlias string       `json:"account_alias"`
+       KeyAlias     string `json:"alias"`
+       Password     string `json:"password"`
+       XPrv         string `json:"xprv"`
+       Index        uint64 `json:"index"`
+       AccountAlias string `json:"account_alias"`
 }
 
 func (bcr *BlockchainReactor) walletExportKey(ctx context.Context, in struct {
index 1a451a8..d86a586 100755 (executable)
@@ -10,7 +10,9 @@ import (
        "github.com/bytom/blockchain/account"
        "github.com/bytom/blockchain/asset"
        "github.com/bytom/blockchain/query"
+       "github.com/bytom/blockchain/signers"
        "github.com/bytom/common"
+       "github.com/bytom/consensus"
        "github.com/bytom/crypto/sha3pool"
        "github.com/bytom/errors"
        "github.com/bytom/protocol/bc"
@@ -19,38 +21,78 @@ import (
 )
 
 // annotateTxs adds asset data to transactions
-func annotateTxsAsset(txs []*query.AnnotatedTx, walletDB db.DB) {
+func annotateTxsAsset(w *Wallet, txs []*query.AnnotatedTx) {
        for i, tx := range txs {
                for j, input := range tx.Inputs {
-                       localAsset, err := getAliasFromAssetID(input.AssetID, walletDB)
-                       if localAsset == nil || err != nil {
+                       alias, definition, err := w.getAliasDefinition(input.AssetID)
+                       if err != nil {
                                continue
                        }
-                       txs[i].Inputs[j].AssetAlias = *localAsset.Alias
+                       txs[i].Inputs[j].AssetAlias = alias
+                       txs[i].Inputs[j].AssetDefinition = &definition
                }
                for j, output := range tx.Outputs {
-                       localAsset, err := getAliasFromAssetID(output.AssetID, walletDB)
-                       if localAsset == nil || err != nil {
+                       alias, definition, err := w.getAliasDefinition(output.AssetID)
+                       if err != nil {
                                continue
                        }
-                       txs[i].Outputs[j].AssetAlias = *localAsset.Alias
+                       txs[i].Outputs[j].AssetAlias = alias
+                       txs[i].Outputs[j].AssetDefinition = &definition
                }
        }
 }
 
-func getAliasFromAssetID(assetID bc.AssetID, walletDB db.DB) (*asset.Asset, error) {
-       var localAsset asset.Asset
-       rawAsset := walletDB.Get(asset.Key(&assetID))
-       if rawAsset == nil {
+func (w *Wallet) getExternalDefinition(assetID *bc.AssetID) (json.RawMessage, error) {
+
+       definitionByte := w.DB.Get(asset.CalcExtAssetKey(assetID))
+       if definitionByte == nil {
                return nil, nil
        }
 
-       if err := json.Unmarshal(rawAsset, &localAsset); err != nil {
-               log.WithFields(log.Fields{"warn": err, "asset id": assetID.String()}).Warn("look up asset")
+       definitionMap := make(map[string]interface{})
+       if err := json.Unmarshal(definitionByte, &definitionMap); err != nil {
                return nil, err
        }
 
-       return &localAsset, nil
+       saveAlias := assetID.String()
+       storeBatch := w.DB.NewBatch()
+
+       externalAsset := &asset.Asset{AssetID: *assetID, Alias: &saveAlias, DefinitionMap: definitionMap, Signer: &signers.Signer{Type: "external"}}
+       if rawAsset, err := json.Marshal(externalAsset); err == nil {
+               log.WithFields(log.Fields{"assetID": assetID.String(), "alias": saveAlias}).Info("index external asset")
+               storeBatch.Set(asset.Key(assetID), rawAsset)
+       }
+       storeBatch.Set(asset.AliasKey(saveAlias), []byte(assetID.String()))
+       storeBatch.Write()
+
+       return definitionByte, nil
+
+}
+
+func (w *Wallet) getAliasDefinition(assetID bc.AssetID) (string, json.RawMessage, error) {
+       //btm
+       if assetID.String() == consensus.BTMAssetID.String() {
+               alias := consensus.BTMAlias
+               definition := []byte(asset.DefaultNativeAsset.RawDefinitionByte)
+
+               return alias, definition, nil
+       }
+
+       //local asset and saved external asset
+       localAsset, err := w.AssetReg.FindByID(nil, &assetID)
+       if err != nil {
+               return "", nil, err
+       }
+       alias := *localAsset.Alias
+       definition := []byte(localAsset.RawDefinitionByte)
+       return alias, definition, nil
+
+       //external asset
+       if definition, err := w.getExternalDefinition(&assetID); definition != nil {
+               return assetID.String(), definition, err
+       }
+
+       return "", nil, fmt.Errorf("look up asset %s :not found ", assetID.String())
 }
 
 // annotateTxs adds account data to transactions
@@ -61,20 +103,20 @@ func annotateTxsAccount(txs []*query.AnnotatedTx, walletDB db.DB) {
                        if input.SpentOutputID == nil {
                                continue
                        }
-                       account, err := getAccountFromUTXO(*input.SpentOutputID, walletDB)
-                       if account == nil || err != nil {
+                       localAccount, err := getAccountFromUTXO(*input.SpentOutputID, walletDB)
+                       if localAccount == nil || err != nil {
                                continue
                        }
-                       txs[i].Inputs[j].AccountAlias = account.Alias
-                       txs[i].Inputs[j].AccountID = account.ID
+                       txs[i].Inputs[j].AccountAlias = localAccount.Alias
+                       txs[i].Inputs[j].AccountID = localAccount.ID
                }
                for j, output := range tx.Outputs {
-                       account, err := getAccountFromACP(output.ControlProgram, walletDB)
-                       if account == nil || err != nil {
+                       localAccount, err := getAccountFromACP(output.ControlProgram, walletDB)
+                       if localAccount == nil || err != nil {
                                continue
                        }
-                       txs[i].Outputs[j].AccountAlias = account.Alias
-                       txs[i].Outputs[j].AccountID = account.ID
+                       txs[i].Outputs[j].AccountAlias = localAccount.Alias
+                       txs[i].Outputs[j].AccountID = localAccount.ID
                }
        }
 }
@@ -168,7 +210,6 @@ func buildAnnotatedInput(tx *legacy.Tx, i uint32) *query.AnnotatedInput {
        orig := tx.Inputs[i]
        in := &query.AnnotatedInput{
                AssetDefinition: &emptyJSONObject,
-               AssetTags:       &emptyJSONObject,
                ReferenceData:   &emptyJSONObject,
        }
        if !orig.IsCoinbase() {
@@ -205,7 +246,6 @@ func buildAnnotatedOutput(tx *legacy.Tx, idx int) *query.AnnotatedOutput {
                Position:        idx,
                AssetID:         *orig.AssetId,
                AssetDefinition: &emptyJSONObject,
-               AssetTags:       &emptyJSONObject,
                Amount:          orig.Amount,
                ControlProgram:  orig.ControlProgram,
                ReferenceData:   &emptyJSONObject,
index 2483345..cb546c4 100755 (executable)
@@ -8,6 +8,7 @@ import (
        "github.com/tendermint/tmlibs/db"
 
        "github.com/bytom/blockchain/account"
+       "github.com/bytom/blockchain/asset"
        "github.com/bytom/blockchain/query"
        "github.com/bytom/crypto/sha3pool"
        "github.com/bytom/errors"
@@ -37,8 +38,8 @@ type accountOutput struct {
 const (
        //TxPrefix is wallet database transactions prefix
        TxPrefix = "TXS:"
-       //TxIndex is wallet database tx index prefix
-       TxIndex = "TID:"
+       //TxIndexPrefix is wallet database tx index prefix
+       TxIndexPrefix = "TID:"
 )
 
 func formatKey(blockHeight uint64, position uint32) string {
@@ -54,7 +55,7 @@ func calcDeleteKey(blockHeight uint64) []byte {
 }
 
 func calcTxIndexKey(txID string) []byte {
-       return []byte(TxIndex + txID)
+       return []byte(TxIndexPrefix + txID)
 }
 
 //deleteTransaction delete transactions when orphan block rollback
@@ -128,10 +129,31 @@ func (w *Wallet) reverseAccountUTXOs(batch db.Batch, b *legacy.Block) {
        }
 }
 
+//save external assets definition
+func saveExternalAssetDefinition(b *legacy.Block, walletDB db.DB) {
+       storeBatch := walletDB.NewBatch()
+       defer storeBatch.Write()
+
+       for _, tx := range b.Transactions {
+               for _, orig := range tx.Inputs {
+                       if ii, ok := orig.TypedInput.(*legacy.IssuanceInput); ok {
+                               if isValidJSON(ii.AssetDefinition) {
+                                       assetID := ii.AssetID()
+                                       if assetExist := walletDB.Get(asset.CalcExtAssetKey(&assetID)); assetExist != nil {
+                                               continue
+                                       }
+                                       storeBatch.Set(asset.CalcExtAssetKey(&assetID), ii.AssetDefinition)
+                               }
+                       }
+               }
+       }
+}
+
 //indexTransactions saves all annotated transactions to the database.
 func (w *Wallet) indexTransactions(batch db.Batch, b *legacy.Block) error {
        annotatedTxs := filterAccountTxs(b, w)
-       annotateTxsAsset(annotatedTxs, w.DB)
+       saveExternalAssetDefinition(b, w.DB)
+       annotateTxsAsset(w, annotatedTxs)
        annotateTxsAccount(annotatedTxs, w.DB)
 
        for _, tx := range annotatedTxs {
index 555e06d..8f14147 100755 (executable)
@@ -127,3 +127,21 @@ var updateAssetTagsCmd = &cobra.Command{
                jww.FEEDBACK.Println("Successfully update asset tags")
        },
 }
+
+var updateAssetAliasCmd = &cobra.Command{
+       Use:   "update-asset-alias <oldAlias> <newAlias>",
+       Short: "Update the asset alias",
+       Args:  cobra.ExactArgs(2),
+       Run: func(cmd *cobra.Command, args []string) {
+               var updateAlias = struct {
+                       OldAlias string `json:"old_alias"`
+                       NewAlias string `json:"new_alias"`
+               }{OldAlias: args[0], NewAlias: args[1]}
+
+               if _, exitCode := util.ClientCall("/update-asset-alias", &updateAlias); exitCode != util.Success {
+                       os.Exit(exitCode)
+               }
+
+               jww.FEEDBACK.Println("Successfully update asset alias")
+       },
+}
index 26c5501..c51b01b 100644 (file)
@@ -87,6 +87,7 @@ func AddCommands() {
        BytomcliCmd.AddCommand(createAssetCmd)
        BytomcliCmd.AddCommand(listAssetsCmd)
        BytomcliCmd.AddCommand(updateAssetTagsCmd)
+       BytomcliCmd.AddCommand(updateAssetAliasCmd)
 
        BytomcliCmd.AddCommand(listTransactionsCmd)
        BytomcliCmd.AddCommand(listUnspentOutputsCmd)
index 4d3b962..37e0b39 100755 (executable)
@@ -45,15 +45,16 @@ func runNode(cmd *cobra.Command, args []string) error {
        if cmn.FileExists(genDocFile) {
                jsonBlob, err := ioutil.ReadFile(genDocFile)
                if err != nil {
-                       return fmt.Errorf("Couldn't read GenesisDoc file: %v", err)
+                       return fmt.Errorf("Couldn't read GenesisDoc file: %v ", err)
                }
                genDoc, err := types.GenesisDocFromJSON(jsonBlob)
                if err != nil {
-                       return fmt.Errorf("Error reading GenesisDoc: %v", err)
+                       return fmt.Errorf("Error reading GenesisDoc: %v ", err)
                }
                if genDoc.ChainID == "" {
-                       return fmt.Errorf("Genesis doc %v must include non-empty chain_id", genDocFile)
+                       return fmt.Errorf("Genesis doc %v must include non-empty chain_id ", genDocFile)
                }
+
                config.ChainID = genDoc.ChainID
                config.PrivateKey = genDoc.PrivateKey
                config.Time = genDoc.GenesisTime
index 530c193..0e98370 100644 (file)
@@ -35,6 +35,26 @@ var BTMAssetID = &bc.AssetID{
        V3: uint64(18446744073709551615),
 }
 
+//BTMAlias is default btm
+var BTMAlias = "btm"
+
+//BTMSymbol
+var BTMSymbol = "btm"
+
+//BTMDecimals
+var BTMDecimals = 8
+
+//BTMDescription
+var BTMDescription = `Bytom Official Issue`
+
+//BTMDefinitionMap
+var BTMDefinitionMap = map[string]interface{}{
+       "name":        BTMAlias,
+       "symbol":      BTMSymbol,
+       "decimals":    BTMDecimals,
+       "description": BTMDescription,
+}
+
 // BlockSubsidy calculate the coinbase rewards on given block height
 func BlockSubsidy(height uint64) uint64 {
        if height == 0 {