OSDN Git Service

d323edc77790942bab6e0635267fdfe197a3804c
[bytom/vapor.git] / asset / builder.go
1 package asset
2
3 import (
4         "context"
5         stdjson "encoding/json"
6         "time"
7
8         log "github.com/sirupsen/logrus"
9
10         "github.com/vapor/blockchain/txbuilder"
11         chainjson "github.com/vapor/encoding/json"
12         "github.com/vapor/errors"
13         "github.com/vapor/protocol/bc"
14         "github.com/vapor/protocol/bc/types"
15 )
16
17 // DecodeCrossInAction convert input data to action struct
18 func (r *Registry) DecodeCrossInAction(data []byte) (txbuilder.Action, error) {
19         a := &crossInAction{reg: r}
20         err := stdjson.Unmarshal(data, a)
21         return a, err
22 }
23
24 type crossInAction struct {
25         reg *Registry
26         bc.AssetAmount
27         SourceID        string                 `json:"source_id"` // AnnotatedUTXO
28         SourcePos       uint64                 `json:"source_pos"`
29         Program         chainjson.HexBytes     `json:"control_program"`
30         AssetDefinition map[string]interface{} `json:"asset_definition"`
31         Arguments       []chainjson.HexBytes   `json:"arguments"`
32 }
33
34 // TODO: also need to hard-code mapTx
35 // TODO: iter cross-in and save asset, saveExternalAssetDefinition
36 // TODO: federation can sign? check arguments length?
37 func (a *crossInAction) Build(ctx context.Context, builder *txbuilder.TemplateBuilder) error {
38         var missing []string
39         if len(a.Program) == 0 {
40                 missing = append(missing, "control_program")
41         }
42         if a.SourceID == "" {
43                 missing = append(missing, "source_id")
44         }
45         if a.AssetId.IsZero() {
46                 missing = append(missing, "asset_id")
47         }
48         if a.Amount == 0 {
49                 missing = append(missing, "amount")
50         }
51         if len(missing) > 0 {
52                 return txbuilder.MissingFieldsError(missing...)
53         }
54
55         var err error
56         asset := &Asset{}
57         if preAsset, _ := a.reg.GetAsset(a.AssetId.String()); preAsset != nil {
58                 asset = preAsset
59         } else {
60                 asset.RawDefinitionByte, err = serializeAssetDef(a.AssetDefinition)
61                 if err != nil {
62                         return ErrSerializing
63                 }
64
65                 if !chainjson.IsValidJSON(asset.RawDefinitionByte) {
66                         return errors.New("asset definition is not in valid json format")
67                 }
68
69                 asset.DefinitionMap = a.AssetDefinition
70                 asset.VMVersion = 1
71                 // TODO: asset.IssuanceProgram
72                 asset.AssetID = *a.AssetId
73                 extAlias := a.AssetId.String()
74                 asset.Alias = &(extAlias)
75                 a.reg.SaveAsset(asset, extAlias)
76         }
77
78         arguments := [][]byte{}
79         for _, argument := range a.Arguments {
80                 arguments = append(arguments, argument)
81         }
82
83         var sourceID bc.Hash
84         if err := sourceID.UnmarshalText([]byte(a.SourceID)); err != nil {
85                 return errors.New("invalid sourceID format")
86         }
87
88         txin := types.NewCrossChainInput(arguments, sourceID, *a.AssetId, a.Amount, a.SourcePos, a.Program, asset.RawDefinitionByte)
89         log.Info("cross-chain input action built")
90         builder.RestrictMinTime(time.Now())
91         return builder.AddInput(txin, &txbuilder.SigningInstruction{})
92 }
93
94 func (a *crossInAction) ActionType() string {
95         return "cross_chain_in"
96 }