OSDN Git Service

fix https://github.com/Bytom/vapor/pull/77#discussion_r286742937
[bytom/vapor.git] / asset / builder.go
index 09325bf..21aa3c8 100644 (file)
@@ -3,41 +3,38 @@ package asset
 import (
        "context"
        stdjson "encoding/json"
+       "fmt"
        "time"
 
        log "github.com/sirupsen/logrus"
 
        "github.com/vapor/blockchain/txbuilder"
+       "github.com/vapor/consensus/federation"
        chainjson "github.com/vapor/encoding/json"
        "github.com/vapor/errors"
        "github.com/vapor/protocol/bc"
        "github.com/vapor/protocol/bc/types"
-       "github.com/vapor/testutil"
 )
 
 // DecodeCrossInAction convert input data to action struct
 func (r *Registry) DecodeCrossInAction(data []byte) (txbuilder.Action, error) {
-       a := &crossInAction{assets: r}
+       a := &crossInAction{reg: r}
        err := stdjson.Unmarshal(data, a)
        return a, err
 }
 
 type crossInAction struct {
-       assets *Registry
+       reg *Registry
        bc.AssetAmount
-       SourceID        string                 `json:"source_id"` // AnnotatedUTXO
+       SourceID        string                 `json:"source_id"`
        SourcePos       uint64                 `json:"source_pos"`
-       Program         chainjson.HexBytes     `json:"control_program"`
        AssetDefinition map[string]interface{} `json:"asset_definition"`
-       UpdateAssetDef  bool                   `json:"update_asset_definition"`
-       Arguments       []chainjson.HexBytes   `json:"arguments"`
 }
 
-// TODO: also need to hard-code mapTx
 func (a *crossInAction) Build(ctx context.Context, builder *txbuilder.TemplateBuilder) error {
        var missing []string
-       if len(a.Program) == 0 {
-               missing = append(missing, "control_program")
+       if a.SourceID == "" {
+               missing = append(missing, "source_id")
        }
        if a.AssetId.IsZero() {
                missing = append(missing, "asset_id")
@@ -49,45 +46,49 @@ func (a *crossInAction) Build(ctx context.Context, builder *txbuilder.TemplateBu
                return txbuilder.MissingFieldsError(missing...)
        }
 
-       // Handle asset definition.
-       // Asset issuance's legality is guaranteed by the federation.
-       rawDefinition, err := serializeAssetDef(a.AssetDefinition)
-       if err != nil {
-               return ErrSerializing
+       sourceKey := []byte(fmt.Sprintf("SC:%v:%v", a.SourceID, a.SourcePos))
+       a.reg.assetMu.Lock()
+       defer a.reg.assetMu.Unlock()
+       if existed := a.reg.db.Get(sourceKey); existed != nil {
+               return errors.New("mainchain output double spent")
        }
-       if preAsset, _ := a.assets.GetAsset(a.AssetId.String()); preAsset != nil {
-               // GetAsset() doesn't unmashall for RawDefinitionBytes, so we need to
-               // serialize DefinitionMap on our own
-               preRawDefinition, err := serializeAssetDef(preAsset.DefinitionMap)
+
+       var err error
+       asset := &Asset{}
+       if preAsset, _ := a.reg.GetAsset(a.AssetId.String()); preAsset != nil {
+               asset = preAsset
+       } else {
+               asset.RawDefinitionByte, err = serializeAssetDef(a.AssetDefinition)
                if err != nil {
                        return ErrSerializing
                }
 
-               if !testutil.DeepEqual(preRawDefinition, rawDefinition) && !a.UpdateAssetDef {
-                       return errors.New("asset definition mismatch with previous definition")
-               } else if !testutil.DeepEqual(preRawDefinition, rawDefinition) {
-                       // update asset def
-                       // TODO: maybe merge with save
-                       if !chainjson.IsValidJSON(rawDefinition) {
-                               return errors.New("asset definition is not in valid json format")
-                       }
+               if !chainjson.IsValidJSON(asset.RawDefinitionByte) {
+                       return errors.New("asset definition is not in valid json format")
                }
-       }
 
-       // TODO: save AssetDefinition
-       if !chainjson.IsValidJSON(rawDefinition) {
-               return errors.New("asset definition is not in valid json format")
+               asset.DefinitionMap = a.AssetDefinition
+               asset.VMVersion = 1
+               asset.AssetID = *a.AssetId
+               extAlias := a.AssetId.String()
+               asset.Alias = &(extAlias)
+               a.reg.SaveExtAsset(asset)
        }
 
-       arguments := [][]byte{}
-       for _, argument := range a.Arguments {
-               arguments = append(arguments, argument)
+       var sourceID bc.Hash
+       if err := sourceID.UnmarshalText([]byte(a.SourceID)); err != nil {
+               return errors.New("invalid sourceID format")
        }
-       sourceID := testutil.MustDecodeHash(a.SourceID)
-       txin := types.NewCrossChainInput(arguments, sourceID, *a.AssetId, a.Amount, a.SourcePos, a.Program, rawDefinition)
-       log.Info("cross-chain input action build")
+
+       fed := federation.GetFederation()
+       // arguments will be set when materializeWitnesses
+       txin := types.NewCrossChainInput(nil, sourceID, *a.AssetId, a.Amount, a.SourcePos, fed.ControlProgram, asset.RawDefinitionByte)
+       log.Info("cross-chain input action built")
        builder.RestrictMinTime(time.Now())
-       return builder.AddInput(txin, &txbuilder.SigningInstruction{})
+       tplIn := &txbuilder.SigningInstruction{}
+       tplIn.AddRawWitnessKeys(fed.XPubs, fed.Path, fed.Quorum)
+       a.reg.db.Set(sourceKey, []byte("true"))
+       return builder.AddInput(txin, tplIn)
 }
 
 func (a *crossInAction) ActionType() string {