OSDN Git Service

Fix mov issue (#462)
[bytom/vapor.git] / consensus / segwit / segwit.go
1 package segwit
2
3 import (
4         "errors"
5
6         "github.com/bytom/vapor/consensus"
7         "github.com/bytom/vapor/protocol/bc"
8         "github.com/bytom/vapor/protocol/vm"
9         "github.com/bytom/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
90         if !IsP2WScript(insts[4].Data) {
91                 return false
92         }
93
94         return insts[5].Op == vm.OP_DATA_32 && len(insts[5].Data) == 32
95 }
96
97 // ConvertP2PKHSigProgram convert standard P2WPKH program into P2PKH program
98 func ConvertP2PKHSigProgram(prog []byte) ([]byte, error) {
99         insts, err := vm.ParseProgram(prog)
100         if err != nil {
101                 return nil, err
102         }
103         if insts[0].Op == vm.OP_0 {
104                 return vmutil.P2PKHSigProgram(insts[1].Data)
105         }
106         return nil, errors.New("unknow P2PKH version number")
107 }
108
109 // ConvertP2SHProgram convert standard P2WSH program into P2SH program
110 func ConvertP2SHProgram(prog []byte) ([]byte, error) {
111         insts, err := vm.ParseProgram(prog)
112         if err != nil {
113                 return nil, err
114         }
115         if insts[0].Op == vm.OP_0 {
116                 return vmutil.P2SHProgram(insts[1].Data)
117         }
118         return nil, errors.New("unknow P2SHP version number")
119 }
120
121 // ConvertP2MCProgram convert standard P2WMC program into P2MC program
122 func ConvertP2MCProgram(prog []byte) ([]byte, error) {
123         magneticContractArgs, err := DecodeP2WMCProgram(prog)
124         if err != nil {
125                 return nil, err
126         }
127         return vmutil.P2MCProgram(*magneticContractArgs)
128 }
129
130 // DecodeP2WMCProgram parse standard P2WMC arguments to magneticContractArgs
131 func DecodeP2WMCProgram(prog []byte) (*vmutil.MagneticContractArgs, error) {
132         if !IsP2WMCScript(prog) {
133                 return nil, errors.New("invalid P2MC program")
134         }
135
136         insts, err := vm.ParseProgram(prog)
137         if err != nil {
138                 return nil, err
139         }
140
141         magneticContractArgs := &vmutil.MagneticContractArgs{
142                 SellerProgram: insts[4].Data,
143                 SellerKey:     insts[5].Data,
144         }
145         requestedAsset := [32]byte{}
146         copy(requestedAsset[:], insts[1].Data)
147         magneticContractArgs.RequestedAsset = bc.NewAssetID(requestedAsset)
148
149         if magneticContractArgs.RatioNumerator, err = vm.AsInt64(insts[2].Data); err != nil {
150                 return nil, err
151         }
152
153         if magneticContractArgs.RatioDenominator, err = vm.AsInt64(insts[3].Data); err != nil {
154                 return nil, err
155         }
156
157         return magneticContractArgs, nil
158 }
159
160 // GetHashFromStandardProg get hash from standard program
161 func GetHashFromStandardProg(prog []byte) ([]byte, error) {
162         insts, err := vm.ParseProgram(prog)
163         if err != nil {
164                 return nil, err
165         }
166
167         return insts[1].Data, nil
168 }