-
Notifications
You must be signed in to change notification settings - Fork 2
/
lib.rs
122 lines (100 loc) · 4.04 KB
/
lib.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
117
118
119
120
121
122
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
use entropy_programs::{
core::{bindgen::*, export_program, prelude::*, SatisfiableForArchitecture, TryParse},
programs::acl::*,
};
use alloc::{
format,
string::{String, ToString},
vec::Vec,
};
use serde::{Deserialize, Serialize};
use serde_json;
pub struct BasicTransaction;
/// JSON-deserializable struct that will be used to derive the program-JSON interface.
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct UserConfig {
pub allowlisted_addresses: Vec<String>,
}
/// JSON representation of the auxiliary data
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct AuxData {}
// TODO confirm this isn't an issue for audit
register_custom_getrandom!(always_fail);
impl Program for BasicTransaction {
/// This is the function that the programs engine will runtime esecute. signature_request is the preimage of the curve element to be
/// signed, eg. RLP-serialized Ethereum transaction request, raw x86_64 executable, etc.
// #[no_mangle]
fn evaluate(
signature_request: SignatureRequest,
config: Option<Vec<u8>>,
_oracle_data: Option<Vec<u8>>,
) -> Result<(), CoreError> {
// parse the raw tx into some type supported by the Acl check
let parsed_tx = <Evm as Architecture>::TransactionRequest::try_parse(
signature_request.message.as_slice(),
)?;
// construct a allowlist ACL from the config
let typed_config = serde_json::from_slice::<UserConfig>(
config
.ok_or(CoreError::Evaluation("No config provided.".to_string()))?
.as_slice(),
)
.map_err(|e| CoreError::Evaluation(format!("Failed to parse config: {}", e)))?;
let addresses: Vec<<Evm as Architecture>::AddressRaw> = typed_config
.allowlisted_addresses
.iter()
.map(|a| hex::decode(a).unwrap().try_into().unwrap())
.collect();
let allowlisted_acl = Acl::<<Evm as Architecture>::AddressRaw> {
addresses,
..Default::default()
};
// check that the parsed tx is allowed by the ACL
allowlisted_acl.is_satisfied_by(&parsed_tx)?;
Ok(())
}
/// Since we don't use a custom hash function, we can just return `None` here.
fn custom_hash(_data: Vec<u8>) -> Option<Vec<u8>> {
None
}
}
export_program!(BasicTransaction);
// write a test that calls evaluate and passes it the proper parameters
#[cfg(test)]
mod tests {
use super::*;
const EVM_TX_WITH_ALLOWLISTED_RECIPIENT: &[u8] = b"0xef01808094772b9a9e8aa1c9db861c6611a82d251db4fac990019243726561746564204f6e20456e74726f7079018080";
const EVM_TX_WITH_NONALLOWLISTED_RECIPIENT: &[u8] = b"0xef01808094772b9a9e8aa1c9db861c6611a82d251db4fac991019243726561746564204f6e20456e74726f7079018080";
const CONFIG: &[u8] = r#"
{
"allowlisted_addresses": [
"772b9a9e8aa1c9db861c6611a82d251db4fac990"
]
}
"#
.as_bytes();
#[test]
fn test_evaluate() {
let signature_request = SignatureRequest {
// `data` is an RLP serialized ETH transaction with the recipient set to `0x772b9a9e8aa1c9db861c6611a82d251db4fac990`
message: EVM_TX_WITH_ALLOWLISTED_RECIPIENT.to_vec(),
auxilary_data: None,
};
assert!(BasicTransaction::evaluate(signature_request, Some(CONFIG.to_vec()), None).is_ok());
}
#[test]
fn test_start_fail() {
let signature_request = SignatureRequest {
// `data` is the same as previous test, but recipient address ends in `1` instead of `0`, so it should fail
message: EVM_TX_WITH_NONALLOWLISTED_RECIPIENT.to_vec(),
auxilary_data: None,
};
assert!(
BasicTransaction::evaluate(signature_request, Some(CONFIG.to_vec()), None).is_err()
);
}
}