OSDN Git Service

Merge pull request #201 from Bytom/v0.1
[bytom/vapor.git] / blockchain / txbuilder / actions.go
index 9837d61..f06c3ed 100644 (file)
@@ -4,15 +4,11 @@ import (
        "context"
        stdjson "encoding/json"
        "errors"
-       "fmt"
-       "io"
-       "os"
-       "strings"
 
-       "github.com/vapor/config"
+       "golang.org/x/crypto/sha3"
 
-       ipfs "github.com/ipfs/go-ipfs-api"
        "github.com/vapor/common"
+       "github.com/vapor/config"
        "github.com/vapor/consensus"
        "github.com/vapor/encoding/json"
        "github.com/vapor/protocol/bc"
@@ -51,9 +47,9 @@ func (a *controlAddressAction) Build(ctx context.Context, b *TemplateBuilder) er
        if err != nil {
                return err
        }
+
        redeemContract := address.ScriptAddress()
        program := []byte{}
-
        switch address.(type) {
        case *common.AddressWitnessPubKeyHash:
                program, err = vmutil.P2WPKHProgram(redeemContract)
@@ -66,7 +62,7 @@ func (a *controlAddressAction) Build(ctx context.Context, b *TemplateBuilder) er
                return err
        }
 
-       out := types.NewTxOutput(*a.AssetId, a.Amount, program)
+       out := types.NewIntraChainOutput(*a.AssetId, a.Amount, program)
        return b.AddOutput(out)
 }
 
@@ -101,7 +97,7 @@ func (a *controlProgramAction) Build(ctx context.Context, b *TemplateBuilder) er
                return MissingFieldsError(missing...)
        }
 
-       out := types.NewTxOutput(*a.AssetId, a.Amount, a.Program)
+       out := types.NewIntraChainOutput(*a.AssetId, a.Amount, a.Program)
        return b.AddOutput(out)
 }
 
@@ -137,7 +133,7 @@ func (a *retireAction) Build(ctx context.Context, b *TemplateBuilder) error {
        if err != nil {
                return err
        }
-       out := types.NewTxOutput(*a.AssetId, a.Amount, program)
+       out := types.NewIntraChainOutput(*a.AssetId, a.Amount, program)
        return b.AddOutput(out)
 }
 
@@ -145,62 +141,173 @@ func (a *retireAction) ActionType() string {
        return "retire"
 }
 
-const (
-       file uint32 = iota
-       data
-)
-
-// DecodeIpfsDataAction convert input data to action struct
-func DecodeIpfsDataAction(data []byte) (Action, error) {
-       a := new(dataAction)
+// DecodeCrossOutAction convert input data to action struct
+func DecodeCrossOutAction(data []byte) (Action, error) {
+       a := new(crossOutAction)
        err := stdjson.Unmarshal(data, a)
        return a, err
 }
 
-type dataAction struct {
+type crossOutAction struct {
        bc.AssetAmount
-       Type uint32 `json:"data_type"`
-       Data string `json:"data"`
-}
-
-func (a *dataAction) Build(ctx context.Context, b *TemplateBuilder) error {
-       var r io.Reader
-
-       switch a.Type {
-       case file:
-               fi, err := os.Stat(a.Data)
-               if os.IsNotExist(err) {
-                       return err
-               }
-               if fi.IsDir() {
-                       return fmt.Errorf("data [%s] is directory", a.Data)
-               }
-               r, err = os.Open(a.Data)
-               if err != nil {
-                       return err
-               }
-       case data:
-               if a.Data == "" {
-                       return errors.New("data is empty")
-               }
-               r = strings.NewReader(a.Data)
+       Address string `json:"address"`
+}
+
+func (a *crossOutAction) Build(ctx context.Context, b *TemplateBuilder) error {
+       var missing []string
+       if a.Address == "" {
+               missing = append(missing, "address")
+       }
+       if a.AssetId.IsZero() {
+               missing = append(missing, "asset_id")
+       }
+       if a.Amount == 0 {
+               missing = append(missing, "amount")
+       }
+       if len(missing) > 0 {
+               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
        }
 
-       sh := ipfs.NewShell(config.CommonConfig.IpfsAddress)
-       cid, err := sh.Add(r)
+       out := types.NewCrossChainOutput(*a.AssetId, a.Amount, program)
+       return b.AddOutput(out)
+}
+
+func (a *crossOutAction) ActionType() string {
+       return "cross_chain_out"
+}
+
+// DecodeVoteOutputAction convert input data to action struct
+func DecodeVoteOutputAction(data []byte) (Action, error) {
+       a := new(voteOutputAction)
+       err := stdjson.Unmarshal(data, a)
+       return a, err
+}
+
+type voteOutputAction struct {
+       bc.AssetAmount
+       Address string        `json:"address"`
+       Vote    json.HexBytes `json:"vote"`
+}
+
+func (a *voteOutputAction) Build(ctx context.Context, b *TemplateBuilder) error {
+       var missing []string
+       if a.Address == "" {
+               missing = append(missing, "address")
+       }
+       if a.AssetId.IsZero() {
+               missing = append(missing, "asset_id")
+       }
+       if a.Amount == 0 {
+               missing = append(missing, "amount")
+       }
+       if len(a.Vote) == 0 {
+               missing = append(missing, "vote")
+       }
+       if len(missing) > 0 {
+               return MissingFieldsError(missing...)
+       }
+
+       address, err := common.DecodeAddress(a.Address, &consensus.ActiveNetParams)
        if err != nil {
                return err
        }
 
-       program, err := vmutil.RetireProgram([]byte(cid))
+       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
        }
-       out := types.NewTxOutput(*a.AssetId, 0, program)
+
+       out := types.NewVoteOutput(*a.AssetId, a.Amount, program, a.Vote)
        return b.AddOutput(out)
 }
 
-func (a *dataAction) ActionType() string {
-       return "ipfs_data"
+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 []byte  `json:"raw_definition_byte"`
+       IssuanceProgram   []byte  `json:"issuance_program"`
+}
+
+func (a *crossInAction) Build(ctx context.Context, builder *TemplateBuilder) error {
+       var missing []string
+       if a.SourceID.IsZero() {
+               missing = append(missing, "source_id")
+       }
+       if a.AssetId.IsZero() {
+               missing = append(missing, "asset_id")
+       }
+       if a.Amount == 0 {
+               missing = append(missing, "amount")
+       }
+
+       if len(missing) > 0 {
+               return MissingFieldsError(missing...)
+       }
+
+       if err := a.checkAssetID(); err != nil {
+               return err
+       }
+
+       // arguments will be set when materializeWitnesses
+       txin := types.NewCrossChainInput(nil, a.SourceID, *a.AssetId, a.Amount, a.SourcePos, a.VMVersion, a.RawDefinitionByte, a.IssuanceProgram)
+       tplIn := &SigningInstruction{}
+       fed := config.CommonConfig.Federation
+       tplIn.AddRawWitnessKeys(fed.Xpubs, nil, fed.Quorum)
+       return builder.AddInput(txin, tplIn)
+}
+
+func (a *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
 }