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
use bytes::Bytes;
use {Opcode, Script, Num};
use keys::AddressHash;
#[derive(Default)]
pub struct Builder {
data: Bytes,
}
impl Builder {
pub fn build_p2pkh(address: &AddressHash) -> Script {
Builder::default()
.push_opcode(Opcode::OP_DUP)
.push_opcode(Opcode::OP_HASH160)
.push_bytes(&**address)
.push_opcode(Opcode::OP_EQUALVERIFY)
.push_opcode(Opcode::OP_CHECKSIG)
.into_script()
}
pub fn build_p2sh(address: &AddressHash) -> Script {
Builder::default()
.push_opcode(Opcode::OP_HASH160)
.push_bytes(&**address)
.push_opcode(Opcode::OP_EQUAL)
.into_script()
}
pub fn build_nulldata(bytes: &[u8]) -> Script {
Builder::default()
.push_opcode(Opcode::OP_RETURN)
.push_bytes(bytes)
.into_script()
}
pub fn push_opcode(mut self, opcode: Opcode) -> Self {
self.data.push(opcode as u8);
self
}
pub fn push_bool(mut self, value: bool) -> Self {
if value {
self.data.push(Opcode::OP_1 as u8);
} else {
self.data.push(Opcode::OP_0 as u8);
}
self
}
pub fn push_num(self, num: Num) -> Self {
self.push_data(&num.to_bytes())
}
pub fn push_bytes(mut self, bytes: &[u8]) -> Self {
let len = bytes.len();
if len < 1 || len > 75 {
panic!(format!("Canot push {} bytes", len));
}
let opcode: Opcode = Opcode::from_u8(((Opcode::OP_PUSHBYTES_1 as usize) + len - 1) as u8)
.expect("value is within [OP_PUSHBYTES_1; OP_PUSHBYTES_75] interval; qed");
self.data.push(opcode as u8);
self.data.extend_from_slice(bytes);
self
}
pub fn push_data(mut self, data: &[u8]) -> Self {
let len = data.len();
if len < Opcode::OP_PUSHDATA1 as usize {
self.data.push(len as u8);
} else if len < 0x100 {
self.data.push(Opcode::OP_PUSHDATA1 as u8);
self.data.push(len as u8);
} else if len < 0x10000 {
self.data.push(Opcode::OP_PUSHDATA2 as u8);
self.data.push(len as u8);
self.data.push((len >> 8) as u8);
} else if len < 0x1_0000_0000 {
self.data.push(Opcode::OP_PUSHDATA4 as u8);
self.data.push(len as u8);
self.data.push((len >> 8) as u8);
self.data.push((len >> 16) as u8);
self.data.push((len >> 24) as u8);
} else {
panic!("Cannot push more than 0x1_0000_0000 bytes");
}
self.data.extend_from_slice(data);
self
}
pub fn return_bytes(mut self, bytes: &[u8]) -> Self {
let len = bytes.len();
if len < 1 || len > 75 {
panic!(format!("Canot push {} bytes", len));
}
let opcode: Opcode = Opcode::from_u8(((Opcode::OP_PUSHBYTES_1 as usize) + len - 1) as u8)
.expect("value is within [OP_PUSHBYTES_1; OP_PUSHBYTES_75] interval; qed");
self.data.push(Opcode::OP_RETURN as u8);
self.data.push(opcode as u8);
self.data.extend_from_slice(bytes);
self
}
pub fn push_invalid_opcode(mut self) -> Self {
self.data.push(0xff);
self
}
pub fn into_script(self) -> Script {
Script::new(self.data)
}
pub fn into_bytes(self) -> Bytes {
self.data
}
}