OSDN Git Service

optimise
[bytom/vapor.git] / consensus / segwit / segwit.go
1 package segwit
2
3 import (
4         "errors"
5
6         "github.com/vapor/consensus"
7         "github.com/vapor/protocol/bc"
8         "github.com/vapor/protocol/vm"
9         "github.com/vapor/protocol/vm/vmutil"
10 )
11
12 // IsP2WScript is used to determine whether it is a P2WScript or not
13 func IsP2WScript(prog []byte) bool {
14         return IsP2WPKHScript(prog) || IsP2WSHScript(prog) || IsStraightforward(prog)
15 }
16
17 // IsStraightforward is used to determine whether it is a Straightforward script or not
18 func IsStraightforward(prog []byte) bool {
19         insts, err := vm.ParseProgram(prog)
20         if err != nil {
21                 return false
22         }
23         if len(insts) != 1 {
24                 return false
25         }
26         return insts[0].Op == vm.OP_TRUE || insts[0].Op == vm.OP_FAIL
27 }
28
29 // IsP2WPKHScript is used to determine whether it is a P2WPKH script or not
30 func IsP2WPKHScript(prog []byte) bool {
31         insts, err := vm.ParseProgram(prog)
32         if err != nil {
33                 return false
34         }
35         if len(insts) != 2 {
36                 return false
37         }
38         if insts[0].Op > vm.OP_16 {
39                 return false
40         }
41         return insts[1].Op == vm.OP_DATA_20 && len(insts[1].Data) == consensus.PayToWitnessPubKeyHashDataSize
42 }
43
44 // IsP2WSHScript is used to determine whether it is a P2WSH script or not
45 func IsP2WSHScript(prog []byte) bool {
46         insts, err := vm.ParseProgram(prog)
47         if err != nil {
48                 return false
49         }
50         if len(insts) != 2 {
51                 return false
52         }
53         if insts[0].Op > vm.OP_16 {
54                 return false
55         }
56         return insts[1].Op == vm.OP_DATA_32 && len(insts[1].Data) == consensus.PayToWitnessScriptHashDataSize
57 }
58
59 // IsP2WMCScript is used to determine whether it is a P2WMC script or not
60 func IsP2WMCScript(prog []byte) bool {
61         insts, err := vm.ParseProgram(prog)
62         if err != nil {
63                 return false
64         }
65
66         if len(insts) != 6 {
67                 return false
68         }
69
70         if insts[0].Op > vm.OP_16 {
71                 return false
72         }
73
74         if insts[1].Op != vm.OP_DATA_32 || len(insts[1].Data) != 32 {
75                 return false
76         }
77
78         if !(insts[2].IsPushdata() && insts[3].IsPushdata() && insts[4].IsPushdata()) {
79                 return false
80         }
81
82         if _, err = vm.AsInt64(insts[2].Data); err != nil {
83                 return false
84         }
85
86         if _, err = vm.AsInt64(insts[3].Data); err != nil {
87                 return false
88         }
89         return insts[5].Op == vm.OP_DATA_32 && len(insts[5].Data) == 32
90 }
91
92 // ConvertP2PKHSigProgram convert standard P2WPKH program into P2PKH program
93 func ConvertP2PKHSigProgram(prog []byte) ([]byte, error) {
94         insts, err := vm.ParseProgram(prog)
95         if err != nil {
96                 return nil, err
97         }
98         if insts[0].Op == vm.OP_0 {
99                 return vmutil.P2PKHSigProgram(insts[1].Data)
100         }
101         return nil, errors.New("unknow P2PKH version number")
102 }
103
104 // ConvertP2SHProgram convert standard P2WSH program into P2SH program
105 func ConvertP2SHProgram(prog []byte) ([]byte, error) {
106         insts, err := vm.ParseProgram(prog)
107         if err != nil {
108                 return nil, err
109         }
110         if insts[0].Op == vm.OP_0 {
111                 return vmutil.P2SHProgram(insts[1].Data)
112         }
113         return nil, errors.New("unknow P2SHP version number")
114 }
115
116 // ConvertP2MCProgram convert standard P2WMC program into P2MC program
117 func ConvertP2MCProgram(prog []byte) ([]byte, error) {
118         magneticContractArgs, err := DecodeP2MCProgram(prog)
119         if err != nil {
120                 return nil, err
121         }
122         return vmutil.P2MCProgram(*magneticContractArgs)
123 }
124
125 // DecodeP2MCProgram parse standard P2WMC arguments to magneticContractArgs
126 func DecodeP2MCProgram(prog []byte) (*vmutil.MagneticContractArgs, error) {
127         insts, err := vm.ParseProgram(prog)
128         if err != nil {
129                 return nil, err
130         }
131
132         if len(insts) != 6 || insts[0].Op != vm.OP_0 {
133                 return nil, errors.New("invalid P2MC program")
134         }
135
136         magneticContractArgs := &vmutil.MagneticContractArgs{
137                 SellerProgram: insts[4].Data,
138                 SellerKey:     insts[5].Data,
139         }
140         requestedAsset := [32]byte{}
141         copy(requestedAsset[:], insts[1].Data)
142         magneticContractArgs.RequestedAsset = bc.NewAssetID(requestedAsset)
143
144         if magneticContractArgs.RatioMolecule, err = vm.AsInt64(insts[2].Data); err != nil {
145                 return nil, err
146         }
147
148         if magneticContractArgs.RatioDenominator, err = vm.AsInt64(insts[3].Data); err != nil {
149                 return nil, err
150         }
151         return magneticContractArgs, nil
152 }
153
154 // GetHashFromStandardProg get hash from standard program
155 func GetHashFromStandardProg(prog []byte) ([]byte, error) {
156         insts, err := vm.ParseProgram(prog)
157         if err != nil {
158                 return nil, err
159         }
160
161         return insts[1].Data, nil
162 }