OSDN Git Service

fix
[bytom/vapor.git] / blockchain / txbuilder / actions.go
index d5baf78..994e03c 100644 (file)
@@ -5,7 +5,10 @@ import (
        stdjson "encoding/json"
        "errors"
 
+       "golang.org/x/crypto/sha3"
+
        "github.com/vapor/common"
+       cfg "github.com/vapor/config"
        "github.com/vapor/consensus"
        "github.com/vapor/encoding/json"
        "github.com/vapor/protocol/bc"
@@ -147,13 +150,14 @@ func DecodeCrossOutAction(data []byte) (Action, error) {
 
 type crossOutAction struct {
        bc.AssetAmount
-       Address string `json:"address"`
+       Address string        `json:"address"`
+       Program json.HexBytes `json:"control_program"`
 }
 
 func (a *crossOutAction) Build(ctx context.Context, b *TemplateBuilder) error {
        var missing []string
-       if a.Address == "" {
-               missing = append(missing, "address")
+       if a.Address == "" && len(a.Program) == 0 {
+               missing = append(missing, "address or program")
        }
        if a.AssetId.IsZero() {
                missing = append(missing, "asset_id")
@@ -165,23 +169,25 @@ func (a *crossOutAction) Build(ctx context.Context, b *TemplateBuilder) error {
                return MissingFieldsError(missing...)
        }
 
-       address, err := common.DecodeAddress(a.Address, &consensus.MainNetParams)
-       if err != nil {
-               return err
-       }
-
-       redeemContract := address.ScriptAddress()
-       program := []byte{}
-       switch address.(type) {
-       case *common.AddressWitnessPubKeyHash:
-               program, err = vmutil.P2WPKHProgram(redeemContract)
-       case *common.AddressWitnessScriptHash:
-               program, err = vmutil.P2WSHProgram(redeemContract)
-       default:
-               return errors.New("unsupport address type")
-       }
-       if err != nil {
-               return err
+       program := a.Program
+       if a.Address != "" {
+               address, err := common.DecodeAddress(a.Address, consensus.BytomMainNetParams(&consensus.ActiveNetParams))
+               if err != nil {
+                       return err
+               }
+
+               redeemContract := address.ScriptAddress()
+               switch address.(type) {
+               case *common.AddressWitnessPubKeyHash:
+                       program, err = vmutil.P2WPKHProgram(redeemContract)
+               case *common.AddressWitnessScriptHash:
+                       program, err = vmutil.P2WSHProgram(redeemContract)
+               default:
+                       return errors.New("unsupport address type")
+               }
+               if err != nil {
+                       return err
+               }
        }
 
        out := types.NewCrossChainOutput(*a.AssetId, a.Amount, program)
@@ -249,3 +255,67 @@ func (a *voteOutputAction) Build(ctx context.Context, b *TemplateBuilder) error
 func (a *voteOutputAction) ActionType() string {
        return "vote_output"
 }
+
+// DecodeCrossInAction convert input data to action struct
+func DecodeCrossInAction(data []byte) (Action, error) {
+       a := new(crossInAction)
+       err := stdjson.Unmarshal(data, a)
+       return a, err
+}
+
+type crossInAction struct {
+       bc.AssetAmount
+       SourceID          bc.Hash       `json:"source_id"`
+       SourcePos         uint64        `json:"source_pos"`
+       VMVersion         uint64        `json:"vm_version"`
+       RawDefinitionByte json.HexBytes `json:"raw_definition_byte"`
+       IssuanceProgram   json.HexBytes `json:"issuance_program"`
+}
+
+func (c *crossInAction) Build(ctx context.Context, builder *TemplateBuilder) error {
+       var missing []string
+       if c.SourceID.IsZero() {
+               missing = append(missing, "source_id")
+       }
+       if c.AssetId.IsZero() {
+               missing = append(missing, "asset_id")
+       }
+       if c.Amount == 0 {
+               missing = append(missing, "amount")
+       }
+
+       if len(missing) > 0 {
+               return MissingFieldsError(missing...)
+       }
+
+       if err := c.checkAssetID(); err != nil {
+               return err
+       }
+
+       // arguments will be set when materializeWitnesses
+       txin := types.NewCrossChainInput(nil, c.SourceID, *c.AssetId, c.Amount, c.SourcePos, c.VMVersion, c.RawDefinitionByte, c.IssuanceProgram)
+       tplIn := &SigningInstruction{}
+       fed := cfg.CommonConfig.Federation
+
+       if !common.IsOpenFederationIssueAsset(c.RawDefinitionByte) {
+               tplIn.AddRawWitnessKeys(fed.Xpubs, cfg.FedAddressPath, fed.Quorum)
+               tplIn.AddDataWitness(cfg.FederationPMultiSigScript(cfg.CommonConfig))
+       }
+
+       return builder.AddInput(txin, tplIn)
+}
+
+func (c *crossInAction) ActionType() string {
+       return "cross_chain_in"
+}
+
+func (c *crossInAction) checkAssetID() error {
+       defHash := bc.NewHash(sha3.Sum256(c.RawDefinitionByte))
+       assetID := bc.ComputeAssetID(c.IssuanceProgram, c.VMVersion, &defHash)
+
+       if *c.AssetId != *consensus.BTMAssetID && assetID != *c.AssetAmount.AssetId {
+               return errors.New("incorrect asset_idincorrect asset_id")
+       }
+
+       return nil
+}