forked from DNAProject/DNA-java-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathContract.java
More file actions
161 lines (144 loc) · 5.03 KB
/
Copy pathContract.java
File metadata and controls
161 lines (144 loc) · 5.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package DNA.Wallets;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.stream.Stream;
import org.bouncycastle.math.ec.ECPoint;
import DNA.UInt160;
import DNA.Core.Scripts.Program;
import DNA.Core.Scripts.ScriptBuilder;
import DNA.Core.Scripts.ScriptOp;
import DNA.IO.BinaryReader;
import DNA.IO.BinaryWriter;
import DNA.IO.Serializable;
/**
* 所有合约的基类
*/
public class Contract implements Serializable {
/**
* 合约脚本代码
*/
public byte[] redeemScript;
/**
* 合约类型
*/
public ContractParameterType[] parameterList;
/**
* 公钥散列值,用于标识该合约在钱包中隶属于哪一个账户
*/
public UInt160 publicKeyHash;
/**
* 合约地址
*/
private String _address;
public String address() {
if (_address == null) {
_address = Wallet.toAddress(scriptHash());
}
return _address;
}
/**
* 脚本散列值
*/
private UInt160 _scriptHash;
public UInt160 scriptHash() {
if (_scriptHash == null) {
_scriptHash = Program.toScriptHash(redeemScript);
}
return _scriptHash;
}
public boolean isStandard() {
if (redeemScript.length != 35) {
return false;
}
if (redeemScript[0] != 33 || redeemScript[34] != ScriptOp.OP_CHECKSIG.getByte()) {
return false;
}
return true;
}
public static Contract create(UInt160 publicKeyHash, ContractParameterType[] parameterList, byte[] redeemScript) {
Contract contract = new Contract();
contract.redeemScript = redeemScript;
contract.parameterList = parameterList;
contract.publicKeyHash = publicKeyHash;
return contract;
}
public static Contract createSignatureContract(ECPoint publicKey) {
Contract contract = new Contract();
contract.redeemScript = createSignatureRedeemScript(publicKey);
contract.parameterList = new ContractParameterType[] { ContractParameterType.Signature };
contract.publicKeyHash = Program.toScriptHash(publicKey.getEncoded(true));
return contract;
}
public static byte[] createSignatureRedeemScript(ECPoint publicKey) {
try (ScriptBuilder sb = new ScriptBuilder()) {
sb.push(publicKey.getEncoded(true));
sb.add(ScriptOp.OP_CHECKSIG);
return sb.toArray();
}
}
public static Contract createMultiSigContract(UInt160 publicKeyHash, int m, ECPoint ...publicKeys) {
Contract contract = new Contract();
contract.redeemScript = createMultiSigRedeemScript(m, publicKeys);
contract.parameterList = Stream.generate(() -> ContractParameterType.Signature).limit(m).toArray(ContractParameterType[]::new);
contract.publicKeyHash = publicKeyHash;
return contract;
}
public static byte[] createMultiSigRedeemScript(int m, ECPoint ...publicKeys) {
if (!(1 <= m && m <= publicKeys.length && publicKeys.length <= 1024))
throw new IllegalArgumentException();
try (ScriptBuilder sb = new ScriptBuilder()) {
sb.push(BigInteger.valueOf(m));
ECPoint[] ecPoint = Arrays.stream(publicKeys).sorted((o1,o2) -> {
if(o1.getYCoord().toString().compareTo(o2.getYCoord().toString()) == 0) {
return o1.getXCoord().toString().compareTo(o2.getXCoord().toString());
}
return o1.getYCoord().toString().compareTo(o2.getYCoord().toString());
}).toArray(ECPoint[]::new);
for (ECPoint publicKey : ecPoint) {
sb.push(publicKey.getEncoded(true));
}
sb.push(BigInteger.valueOf(publicKeys.length));
sb.add(ScriptOp.OP_CHECKMULTISIG);
return sb.toArray();
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Contract)) {
return false;
}
return scriptHash().equals(((Contract) obj).scriptHash());
}
@Override
public int hashCode() {
return scriptHash().hashCode();
}
@Override
public void deserialize(BinaryReader reader) throws IOException {
try {
publicKeyHash = reader.readSerializable(UInt160.class);
} catch (InstantiationException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
byte[] buffer = reader.readVarBytes();
parameterList = new ContractParameterType[buffer.length];
for (int i = 0; i < parameterList.length; i++) {
parameterList[i] = ContractParameterType.values()[buffer[i]];
}
redeemScript = reader.readVarBytes();
}
@Override
public void serialize(BinaryWriter writer) throws IOException {
writer.writeSerializable(publicKeyHash);
byte[] buffer = new byte[parameterList.length];
for (int i = 0; i < buffer.length; i++) {
buffer[i] = (byte)parameterList[i].ordinal();
}
writer.writeVarBytes(buffer);
writer.writeVarBytes(redeemScript);
}
}