OSDN Git Service

fix https://github.com/Bytom/vapor/pull/77#discussion_r286744128
[bytom/vapor.git] / asset / builder.go
1 package asset
2
3 import (
4         "context"
5         stdjson "encoding/json"
6         "fmt"
7         "time"
8
9         log "github.com/sirupsen/logrus"
10
11         "github.com/vapor/blockchain/txbuilder"
12         "github.com/vapor/consensus/federation"
13         chainjson "github.com/vapor/encoding/json"
14         "github.com/vapor/errors"
15         "github.com/vapor/protocol/bc"
16         "github.com/vapor/protocol/bc/types"
17 )
18
19 // DecodeCrossInAction convert input data to action struct
20 func (r *Registry) DecodeCrossInAction(data []byte) (txbuilder.Action, error) {
21         a := &crossInAction{reg: r}
22         err := stdjson.Unmarshal(data, a)
23         return a, err
24 }
25
26 type crossInAction struct {
27         reg *Registry
28         bc.AssetAmount
29         SourceID        bc.Hash                `json:"source_id"`
30         SourcePos       uint64                 `json:"source_pos"`
31         AssetDefinition map[string]interface{} `json:"asset_definition"`
32 }
33
34 func (a *crossInAction) Build(ctx context.Context, builder *txbuilder.TemplateBuilder) error {
35         var missing []string
36         if a.SourceID.IsZero() {
37                 missing = append(missing, "source_id")
38         }
39         if a.AssetId.IsZero() {
40                 missing = append(missing, "asset_id")
41         }
42         if a.Amount == 0 {
43                 missing = append(missing, "amount")
44         }
45         if len(missing) > 0 {
46                 return txbuilder.MissingFieldsError(missing...)
47         }
48
49         sourceKey := []byte(fmt.Sprintf("SC:%v:%v", a.SourceID, a.SourcePos))
50         a.reg.assetMu.Lock()
51         defer a.reg.assetMu.Unlock()
52         if existed := a.reg.db.Get(sourceKey); existed != nil {
53                 return errors.New("mainchain output double spent")
54         }
55
56         var err error
57         asset := &Asset{}
58         if preAsset, _ := a.reg.GetAsset(a.AssetId.String()); preAsset != nil {
59                 asset = preAsset
60         } else {
61                 asset.RawDefinitionByte, err = serializeAssetDef(a.AssetDefinition)
62                 if err != nil {
63                         return ErrSerializing
64                 }
65
66                 if !chainjson.IsValidJSON(asset.RawDefinitionByte) {
67                         return errors.New("asset definition is not in valid json format")
68                 }
69
70                 asset.DefinitionMap = a.AssetDefinition
71                 asset.VMVersion = 1
72                 asset.AssetID = *a.AssetId
73                 extAlias := a.AssetId.String()
74                 asset.Alias = &(extAlias)
75                 a.reg.SaveExtAsset(asset)
76         }
77
78         fed := federation.GetFederation()
79         // arguments will be set when materializeWitnesses
80         txin := types.NewCrossChainInput(nil, a.SourceID, *a.AssetId, a.Amount, a.SourcePos, fed.ControlProgram, asset.RawDefinitionByte)
81         log.Info("cross-chain input action built")
82         builder.RestrictMinTime(time.Now())
83         tplIn := &txbuilder.SigningInstruction{}
84         tplIn.AddRawWitnessKeys(fed.XPubs, fed.Path, fed.Quorum)
85         a.reg.db.Set(sourceKey, []byte("true"))
86         return builder.AddInput(txin, tplIn)
87 }
88
89 func (a *crossInAction) ActionType() string {
90         return "cross_chain_in"
91 }