-
Notifications
You must be signed in to change notification settings - Fork 219
/
script.rs
116 lines (97 loc) · 3.39 KB
/
script.rs
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
use faster_hex::hex_encode;
use hash::blake2b_256;
use numext_fixed_hash::{h256, H256};
use occupied_capacity::OccupiedCapacity;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
use std::io::Write;
use std::mem;
pub const ALWAYS_SUCCESS_HASH: H256 = h256!("0x1");
// TODO: when flatbuffer work is done, remove Serialize/Deserialize here and
// implement proper From trait
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct Script {
pub args: Vec<Vec<u8>>,
// Binary hash here can be used to refer to binary in one of the dep
// cells of current transaction. The hash here must match the hash of
// cell data so as to reference a dep cell.
pub binary_hash: H256,
}
fn prefix_hex(bytes: &[u8]) -> String {
let mut dst = vec![0u8; bytes.len() * 2 + 2];
dst[0] = b'0';
dst[1] = b'x';
let _ = hex_encode(bytes, &mut dst[2..]);
unsafe { String::from_utf8_unchecked(dst) }
}
impl fmt::Debug for Script {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Script {{ args: ")?;
f.debug_list()
.entries(self.args.iter().map(|arg| prefix_hex(arg)))
.finish()?;
write!(f, ", binary_hash: {:#x}", self.binary_hash,)?;
write!(f, " }}")
}
}
type ScriptTuple = (Vec<Vec<u8>>, H256);
const VEC_WRITE_ALL_EXPECT: &str =
"Essentially, Vec::write_all invoke extend_from_slice, should not fail";
impl Script {
pub fn new(args: Vec<Vec<u8>>, binary_hash: H256) -> Self {
Script { args, binary_hash }
}
pub fn always_success() -> Self {
Self::new(vec![], ALWAYS_SUCCESS_HASH)
}
pub fn destruct(self) -> ScriptTuple {
let Script { args, binary_hash } = self;
(args, binary_hash)
}
pub fn hash(&self) -> H256 {
let mut bytes = vec![];
bytes
.write_all(self.binary_hash.as_bytes())
.expect(VEC_WRITE_ALL_EXPECT);
for argument in &self.args {
bytes.write_all(argument).expect(VEC_WRITE_ALL_EXPECT);
}
blake2b_256(bytes).into()
}
}
impl OccupiedCapacity for Script {
fn occupied_capacity(&self) -> usize {
mem::size_of::<u8>() + self.args.occupied_capacity() + self.binary_hash.occupied_capacity()
}
}
#[cfg(test)]
mod tests {
use super::{Script, H256};
use hash::blake2b_256;
#[test]
fn empty_script_hash() {
let script = Script::new(vec![], H256::zero());
let expect =
H256::from_hex_str("266cec97cbede2cfbce73666f08deed9560bdf7841a7a5a51b3a3f09da249e21")
.unwrap();
assert_eq!(script.hash(), expect);
}
#[test]
fn always_success_script_hash() {
let always_success = include_bytes!("../../nodes_template/spec/cells/always_success");
let always_success_hash: H256 = (&blake2b_256(&always_success[..])).into();
let script = Script::new(vec![], always_success_hash);
let expect =
H256::from_hex_str("9a9a6bdbc38d4905eace1822f85237e3a1e238bb3f277aa7b7c8903441123510")
.unwrap();
assert_eq!(script.hash(), expect);
}
#[test]
fn one_script_hash() {
let one = Script::new(vec![vec![1]], H256::zero());
let expect =
H256::from_hex_str("dade0e507e27e2a5995cf39c8cf454b6e70fa80d03c1187db7a4cb2c9eab79da")
.unwrap();
assert_eq!(one.hash(), expect);
}
}