OSDN Git Service

add dex program
authoroys <oys@oysdeMacBook-Pro.local>
Tue, 24 Sep 2019 11:27:01 +0000 (19:27 +0800)
committeroys <oys@oysdeMacBook-Pro.local>
Tue, 24 Sep 2019 11:27:01 +0000 (19:27 +0800)
consensus/segwit/segwit.go
protocol/validation/vmcontext.go
protocol/vm/vmutil/script.go

index 5f62f33..0f6b08e 100644 (file)
@@ -4,6 +4,7 @@ import (
        "errors"
 
        "github.com/vapor/consensus"
+       "github.com/vapor/protocol/bc"
        "github.com/vapor/protocol/vm"
        "github.com/vapor/protocol/vm/vmutil"
 )
@@ -51,6 +52,20 @@ func IsP2WSHScript(prog []byte) bool {
        return insts[1].Op == vm.OP_DATA_32 && len(insts[1].Data) == consensus.PayToWitnessScriptHashDataSize
 }
 
+func IsP2WDCScript(prog []byte) bool {
+       insts, err := vm.ParseProgram(prog)
+       if err != nil {
+               return false
+       }
+       if len(insts) != 6 {
+               return false
+       }
+       if insts[0].Op > vm.OP_16 {
+               return false
+       }
+       return insts[1].Op == vm.OP_DATA_20 && len(insts[1].Data) == 32 && insts[5].Op == vm.OP_DATA_20 && len(insts[5].Data) == 32
+}
+
 func ConvertP2PKHSigProgram(prog []byte) ([]byte, error) {
        insts, err := vm.ParseProgram(prog)
        if err != nil {
@@ -73,6 +88,33 @@ func ConvertP2SHProgram(prog []byte) ([]byte, error) {
        return nil, errors.New("unknow P2SHP version number")
 }
 
+func ConvertP2DCProgram(prog []byte, lockedAssetID bc.AssetID) ([]byte, error) {
+       insts, err := vm.ParseProgram(prog)
+       if err != nil {
+               return nil, err
+       }
+
+       if insts[0].Op == vm.OP_0 {
+               dexContractArgs := vmutil.DexContractArgs{}
+               var requestedAsset [32]byte
+               copy(requestedAsset[:], insts[1].Data)
+               dexContractArgs.RequestedAsset = bc.NewAssetID(requestedAsset)
+
+               if dexContractArgs.RatioMolecule, err = vm.AsInt64(insts[2].Data); err != nil {
+                       return nil, err
+               }
+
+               if dexContractArgs.RatioDenominator, err = vm.AsInt64(insts[3].Data); err != nil {
+                       return nil, err
+               }
+
+               dexContractArgs.SellerProgram = insts[4].Data
+               dexContractArgs.SellerKey = insts[5].Data
+               return vmutil.P2DCProgram(dexContractArgs, lockedAssetID)
+       }
+       return nil, errors.New("unknow P2DC version number")
+}
+
 func GetHashFromStandardProg(prog []byte) ([]byte, error) {
        insts, err := vm.ParseProgram(prog)
        if err != nil {
index 7ac617c..507b2ef 100644 (file)
@@ -75,9 +75,11 @@ func NewTxVMContext(vs *validationState, entry bc.Entry, prog *bc.Program, args
                entries: tx.Entries,
        }
 
+       AssetIDBytes := [32]byte{}
+       copy(AssetIDBytes[:], (*assetID)[:])
        result := &vm.Context{
                VMVersion: prog.VmVersion,
-               Code:      witnessProgram(prog.Code),
+               Code:      witnessProgram(prog.Code, bc.NewAssetID(AssetIDBytes)),
                Arguments: args,
 
                EntryID: entryID.Bytes(),
@@ -97,13 +99,17 @@ func NewTxVMContext(vs *validationState, entry bc.Entry, prog *bc.Program, args
        return result
 }
 
-func witnessProgram(prog []byte) []byte {
+func witnessProgram(prog []byte, assetID bc.AssetID) []byte {
        if segwit.IsP2WPKHScript(prog) {
-               if witnessProg, err := segwit.ConvertP2PKHSigProgram([]byte(prog)); err == nil {
+               if witnessProg, err := segwit.ConvertP2PKHSigProgram(prog); err == nil {
                        return witnessProg
                }
        } else if segwit.IsP2WSHScript(prog) {
-               if witnessProg, err := segwit.ConvertP2SHProgram([]byte(prog)); err == nil {
+               if witnessProg, err := segwit.ConvertP2SHProgram(prog); err == nil {
+                       return witnessProg
+               }
+       } else if segwit.IsP2WDCScript(prog) {
+               if witnessProg, err := segwit.ConvertP2DCProgram(prog, assetID); err == nil {
                        return witnessProg
                }
        }
index adc0d77..a15f5de 100644 (file)
@@ -1,8 +1,11 @@
 package vmutil
 
 import (
+       "strings"
+
        "github.com/vapor/crypto/ed25519"
        "github.com/vapor/errors"
+       "github.com/vapor/protocol/bc"
        "github.com/vapor/protocol/vm"
 )
 
@@ -133,3 +136,158 @@ func checkMultiSigParams(nrequired, npubkeys int64) error {
        }
        return nil
 }
+
+// DexContractArgs is a struct for dex contract arguments
+type DexContractArgs struct {
+       RequestedAsset   bc.AssetID
+       RatioMolecule    int64
+       RatioDenominator int64
+       SellerProgram    []byte
+       SellerKey        ed25519.PublicKey
+}
+
+// P2WDCProgram return the segwit pay to dex contract
+func P2WDCProgram(dexContractArgs DexContractArgs, lockedAssetID bc.AssetID) ([]byte, error) {
+       builder := NewBuilder()
+       builder.AddInt64(0)
+       builder.AddData(dexContractArgs.RequestedAsset.Bytes())
+       builder.AddInt64(dexContractArgs.RatioMolecule)
+       builder.AddInt64(dexContractArgs.RatioDenominator)
+       builder.AddData(dexContractArgs.SellerProgram)
+       builder.AddData(dexContractArgs.SellerKey)
+       return builder.Build()
+}
+
+// P2DCProgram generates the script for control with dex contract
+func P2DCProgram(dexContractArgs DexContractArgs, lockedAssetID bc.AssetID) ([]byte, error) {
+       standardProgram, err := P2WDCProgram(dexContractArgs, lockedAssetID)
+       if err != nil {
+               return nil, err
+       }
+
+       dexProgram, err := DexProgram(strings.Compare(dexContractArgs.RequestedAsset.String(), lockedAssetID.String()))
+       if err != nil {
+               return nil, err
+       }
+
+       builder := NewBuilder()
+       builder.AddData(dexContractArgs.SellerKey)
+       builder.AddData(standardProgram)
+       builder.AddData(dexContractArgs.SellerProgram)
+       builder.AddInt64(dexContractArgs.RatioDenominator)
+       builder.AddInt64(dexContractArgs.RatioMolecule)
+       builder.AddData(dexContractArgs.RequestedAsset.Bytes())
+       builder.AddOp(vm.OP_DEPTH)
+       builder.AddData(dexProgram)
+       builder.AddOp(vm.OP_FALSE)
+       builder.AddOp(vm.OP_CHECKPREDICATE)
+       return builder.Build()
+}
+
+// DexProgram is the actual execute dex program which not contain arguments
+func DexProgram(assetComparedResult int) ([]byte, error) {
+       var firstPositionOP, secondPostionOP vm.Op
+       if assetComparedResult == 0 {
+               return nil, errors.WithDetail(ErrBadValue, "the requestAssetID is same as lockedAssetID")
+       } else if assetComparedResult > 0 {
+               firstPositionOP = vm.OP_0
+               secondPostionOP = vm.OP_1
+       } else {
+               firstPositionOP = vm.OP_2
+               secondPostionOP = vm.OP_3
+       }
+
+       builder := NewBuilder()
+       builder.AddOp(vm.OP_6)
+       builder.AddOp(vm.OP_ROLL)
+       builder.AddJumpIf(0)
+       builder.AddOp(vm.OP_AMOUNT)
+       builder.AddOp(vm.OP_2)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_MUL)
+       builder.AddOp(vm.OP_3)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_DIV)
+       builder.AddOp(vm.OP_7)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_0)
+       builder.AddOp(vm.OP_GREATERTHAN)
+       builder.AddOp(vm.OP_8)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_2)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_LESSTHANOREQUAL)
+       builder.AddOp(vm.OP_BOOLAND)
+       builder.AddOp(vm.OP_VERIFY)
+       builder.AddOp(vm.OP_7)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_4)
+       builder.AddOp(vm.OP_ROLL)
+       builder.AddOp(vm.OP_MUL)
+       builder.AddOp(vm.OP_3)
+       builder.AddOp(vm.OP_ROLL)
+       builder.AddOp(vm.OP_DIV)
+       builder.AddOp(vm.OP_AMOUNT)
+       builder.AddOp(vm.OP_OVER)
+       builder.AddOp(vm.OP_0)
+       builder.AddOp(vm.OP_GREATERTHAN)
+       builder.AddOp(vm.OP_2)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_ROT)
+       builder.AddOp(vm.OP_LESSTHANOREQUAL)
+       builder.AddOp(vm.OP_BOOLAND)
+       builder.AddOp(vm.OP_VERIFY)
+       builder.AddOp(vm.OP_6)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_2)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_LESSTHAN)
+       builder.AddOp(vm.OP_NOT)
+       builder.AddOp(vm.OP_NOP)
+       builder.AddJumpIf(1)
+       builder.AddOp(firstPositionOP)
+       builder.AddOp(vm.OP_7)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_4)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_1)
+       builder.AddOp(vm.OP_7)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_CHECKOUTPUT)
+       builder.AddOp(vm.OP_VERIFY)
+       builder.AddOp(secondPostionOP)
+       builder.AddOp(vm.OP_AMOUNT)
+       builder.AddOp(vm.OP_2)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_SUB)
+       builder.AddOp(vm.OP_ASSET)
+       builder.AddOp(vm.OP_1)
+       builder.AddOp(vm.OP_8)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_CHECKOUTPUT)
+       builder.AddOp(vm.OP_VERIFY)
+       builder.AddJump(2)
+       builder.SetJumpTarget(1)
+       builder.AddOp(firstPositionOP)
+       builder.AddOp(vm.OP_2)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_4)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_1)
+       builder.AddOp(vm.OP_7)
+       builder.AddOp(vm.OP_PICK)
+       builder.AddOp(vm.OP_CHECKOUTPUT)
+       builder.AddOp(vm.OP_VERIFY)
+       builder.SetJumpTarget(2)
+       builder.AddJump(3)
+       builder.SetJumpTarget(0)
+       builder.AddOp(vm.OP_6)
+       builder.AddOp(vm.OP_ROLL)
+       builder.AddOp(vm.OP_6)
+       builder.AddOp(vm.OP_ROLL)
+       builder.AddOp(vm.OP_TXSIGHASH)
+       builder.AddOp(vm.OP_SWAP)
+       builder.AddOp(vm.OP_CHECKSIG)
+       builder.SetJumpTarget(3)
+       return builder.Build()
+}