unc_sdk/environment/
env.rs

1//! Blockchain-specific methods available to the smart contract. This is a wrapper around a
2//! low-level `BlockchainInterface`. Unless you know what you are doing prefer using `env::*`
3//! whenever possible. In case of cross-contract calls prefer using even higher-level API available
4//! through `callback_args`, `callback_args_vec`, `ext_contract`, `Promise`, and `PromiseOrValue`.
5
6use std::convert::TryInto;
7use std::mem::{size_of, size_of_val};
8use std::panic as std_panic;
9use std::{convert::TryFrom, mem::MaybeUninit};
10
11#[cfg(all(not(target_arch = "wasm32"), feature = "unit-testing"))]
12use crate::mock::MockedBlockchain;
13use crate::promise::Allowance;
14use crate::types::{
15    AccountId, BlockHeight, Gas, PromiseIndex, PromiseResult, PublicKey, StorageUsage, UncToken,
16};
17use crate::{CryptoHash, GasWeight, PromiseError};
18use unc_sys as sys;
19
20const REGISTER_EXPECTED_ERR: &str =
21    "Register was expected to have data because we just wrote it into it.";
22
23/// Register used internally for atomic operations. This register is safe to use by the user,
24/// since it only needs to be untouched while methods of `Environment` execute, which is guaranteed
25/// guest code is not parallel.
26const ATOMIC_OP_REGISTER: u64 = std::u64::MAX - 2;
27/// Register used to record evicted values from the storage.
28const EVICTED_REGISTER: u64 = std::u64::MAX - 1;
29
30/// Key used to store the state of the contract.
31const STATE_KEY: &[u8] = b"STATE";
32
33/// The minimum length of a valid account ID.
34const MIN_ACCOUNT_ID_LEN: u64 = 2;
35/// The maximum length of a valid account ID.
36const MAX_ACCOUNT_ID_LEN: u64 = 64;
37
38fn expect_register<T>(option: Option<T>) -> T {
39    option.unwrap_or_else(|| panic_str(REGISTER_EXPECTED_ERR))
40}
41
42/// A simple macro helper to read blob value coming from host's method.
43macro_rules! try_method_into_register {
44    ( $method:ident ) => {{
45        unsafe { sys::$method(ATOMIC_OP_REGISTER) };
46        read_register(ATOMIC_OP_REGISTER)
47    }};
48}
49
50/// Same as `try_method_into_register` but expects the data.
51macro_rules! method_into_register {
52    ( $method:ident ) => {{
53        expect_register(try_method_into_register!($method))
54    }};
55}
56
57//* Note: need specific length functions because const generics don't work with mem::transmute
58//* https://github.com/rust-lang/rust/issues/61956
59
60pub(crate) unsafe fn read_register_fixed_20(register_id: u64) -> [u8; 20] {
61    let mut hash = [MaybeUninit::<u8>::uninit(); 20];
62    sys::read_register(register_id, hash.as_mut_ptr() as _);
63    std::mem::transmute(hash)
64}
65
66pub(crate) unsafe fn read_register_fixed_32(register_id: u64) -> [u8; 32] {
67    let mut hash = [MaybeUninit::<u8>::uninit(); 32];
68    sys::read_register(register_id, hash.as_mut_ptr() as _);
69    std::mem::transmute(hash)
70}
71
72pub(crate) unsafe fn read_register_fixed_64(register_id: u64) -> [u8; 64] {
73    let mut hash = [MaybeUninit::<u8>::uninit(); 64];
74    sys::read_register(register_id, hash.as_mut_ptr() as _);
75    std::mem::transmute(hash)
76}
77
78/// Replaces the current low-level blockchain interface accessible through `env::*` with another
79/// low-level blockchain interfacr that implements `BlockchainInterface` trait. In most cases you
80/// want to use `testing_env!` macro to set it.
81///
82/// ```
83/// # let context = unc_sdk::test_utils::VMContextBuilder::new().build();
84/// # let vm_config = unc_sdk::test_vm_config();
85/// # let fees_config = unc_sdk::RuntimeFeesConfig::test();
86/// # let storage = Default::default();
87/// # let validators = Default::default();
88/// let mocked_blockchain = unc_sdk::MockedBlockchain::new(
89///           context,
90///           vm_config,
91///           fees_config,
92///           vec![],
93///           storage,
94///           validators,
95///           None,
96///       );
97/// unc_sdk::env::set_blockchain_interface(mocked_blockchain);
98/// ```
99#[cfg(all(not(target_arch = "wasm32"), feature = "unit-testing"))]
100pub fn set_blockchain_interface(blockchain_interface: MockedBlockchain) {
101    crate::mock::with_mocked_blockchain(|b| {
102        *b = blockchain_interface;
103    })
104}
105
106/// Implements panic hook that converts `PanicInfo` into a string and provides it through the
107/// blockchain interface.
108fn panic_hook_impl(info: &std_panic::PanicInfo) {
109    panic_str(info.to_string().as_str());
110}
111
112/// Setups panic hook to expose error info to the blockchain.
113pub fn setup_panic_hook() {
114    std_panic::set_hook(Box::new(panic_hook_impl));
115}
116
117/// Reads the content of the `register_id`. If register is not used returns `None`.
118pub fn read_register(register_id: u64) -> Option<Vec<u8>> {
119    // Get register length and convert to a usize. The max register size in config is much less
120    // than the u32 max so the abort should never be hit, but is there for safety because there
121    // would be undefined behaviour during `read_register` if the buffer length is truncated.
122    let len: usize = register_len(register_id)?.try_into().unwrap_or_else(|_| abort());
123
124    // Initialize buffer with capacity.
125    let mut buffer = Vec::with_capacity(len);
126
127    // Read register into buffer.
128    //* SAFETY: This is safe because the buffer is initialized with the exact capacity of the
129    //*         register that is being read from.
130    unsafe {
131        sys::read_register(register_id, buffer.as_mut_ptr() as u64);
132
133        // Set updated length after writing to buffer.
134        buffer.set_len(len);
135    }
136    Some(buffer)
137}
138
139/// Returns the size of the register. If register is not used returns `None`.
140pub fn register_len(register_id: u64) -> Option<u64> {
141    let len = unsafe { sys::register_len(register_id) };
142    if len == std::u64::MAX {
143        None
144    } else {
145        Some(len)
146    }
147}
148
149// ###############
150// # Context API #
151// ###############
152/// The id of the account that owns the current contract.
153pub fn current_account_id() -> AccountId {
154    assert_valid_account_id(method_into_register!(current_account_id))
155}
156
157/// The id of the account that either signed the original transaction or issued the initial
158/// cross-contract call.
159pub fn signer_account_id() -> AccountId {
160    assert_valid_account_id(method_into_register!(signer_account_id))
161}
162
163/// The public key of the account that did the signing.
164pub fn signer_account_pk() -> PublicKey {
165    PublicKey::try_from(method_into_register!(signer_account_pk)).unwrap_or_else(|_| abort())
166}
167
168/// The id of the account that was the previous contract in the chain of cross-contract calls.
169/// If this is the first contract, it is equal to `signer_account_id`.
170pub fn predecessor_account_id() -> AccountId {
171    assert_valid_account_id(method_into_register!(predecessor_account_id))
172}
173
174/// Helper function to convert and check the account ID from bytes from the runtime.
175fn assert_valid_account_id(bytes: Vec<u8>) -> AccountId {
176    String::from_utf8(bytes)
177        .ok()
178        .and_then(|s| AccountId::try_from(s).ok())
179        .unwrap_or_else(|| abort())
180}
181
182/// The input to the contract call serialized as bytes. If input is not provided returns `None`.
183pub fn input() -> Option<Vec<u8>> {
184    try_method_into_register!(input)
185}
186
187/// Current block index.
188#[deprecated(since = "2.0.0", note = "Use block_height instead")]
189pub fn block_index() -> BlockHeight {
190    block_height()
191}
192
193/// Returns the height of the block the transaction is being executed in.
194pub fn block_height() -> BlockHeight {
195    unsafe { sys::block_height() }
196}
197
198/// Current block timestamp, i.e, number of non-leap-nanoseconds since January 1, 1970 0:00:00 UTC.
199pub fn block_timestamp() -> u64 {
200    unsafe { sys::block_timestamp() }
201}
202
203/// Current block timestamp, i.e, number of non-leap-milliseconds since January 1, 1970 0:00:00 UTC.
204pub fn block_timestamp_ms() -> u64 {
205    block_timestamp() / 1_000_000
206}
207
208/// Current epoch height.
209pub fn epoch_height() -> u64 {
210    unsafe { sys::epoch_height() }
211}
212
213/// Current total storage usage of this smart contract that this account would be paying for.
214pub fn storage_usage() -> StorageUsage {
215    unsafe { sys::storage_usage() }
216}
217
218// #################
219// # Economics API #
220// #################
221/// The balance attached to the given account. This includes the attached_deposit that was
222/// attached to the transaction
223pub fn account_balance() -> UncToken {
224    let data = [0u8; size_of::<UncToken>()];
225    unsafe { sys::account_balance(data.as_ptr() as u64) };
226    UncToken::from_attounc(u128::from_le_bytes(data))
227}
228
229/// The balance locked for potential validator staking.
230pub fn account_locked_balance() -> UncToken {
231    let data = [0u8; size_of::<UncToken>()];
232    unsafe { sys::account_locked_balance(data.as_ptr() as u64) };
233    UncToken::from_attounc(u128::from_le_bytes(data))
234}
235
236/// The balance that was attached to the call that will be immediately deposited before the
237/// contract execution starts
238pub fn attached_deposit() -> UncToken {
239    let data = [0u8; size_of::<UncToken>()];
240    unsafe { sys::attached_deposit(data.as_ptr() as u64) };
241    UncToken::from_attounc(u128::from_le_bytes(data))
242}
243
244/// The amount of gas attached to the call that can be used to pay for the gas fees.
245pub fn prepaid_gas() -> Gas {
246    Gas::from_gas(unsafe { sys::prepaid_gas() })
247}
248
249/// The gas that was already burnt during the contract execution (cannot exceed `prepaid_gas`)
250pub fn used_gas() -> Gas {
251    Gas::from_gas(unsafe { sys::used_gas() })
252}
253
254// ############
255// # Math API #
256// ############
257
258/// Returns the random seed from the current block. This 32 byte hash is based on the VRF value from
259/// the block. This value is not modified in any way each time this function is called within the
260/// same method/block.
261pub fn random_seed() -> Vec<u8> {
262    random_seed_array().to_vec()
263}
264
265/// Returns the random seed from the current block. This 32 byte hash is based on the VRF value from
266/// the block. This value is not modified in any way each time this function is called within the
267/// same method/block.
268/// Example of usage:
269/// ```rust
270/// use rand::{Rng, SeedableRng};
271/// use rand_chacha::ChaCha20Rng;
272/// use unc_sdk::unc;
273/// use unc_sdk::env;
274/// #[unc(contract_state)]
275/// struct RngExample {
276///    val: i32,
277/// }
278/// #[unc]
279/// impl RngExample {
280///     pub fn increment(&mut self) {
281///         let mut rng = ChaCha20Rng::from_seed(env::random_seed_array());
282///         let value = rng.gen_range(0..1011);
283///         self.val += value;
284///     }
285///     pub fn get_value(&mut self) -> i32 {
286///         self.val
287///     }
288/// }
289/// ```
290///
291/// Example of usage with [unc-rng](https://lib.rs/crates/unc-rng) which allows to decrease size of contract binary:
292///
293/// ```rust
294/// use unc_rng::Rng;
295/// use unc_sdk::unc;
296/// use unc_sdk::env;
297/// #[unc(contract_state)]
298/// struct UncRngExample {
299///    val: i32,
300/// }
301/// #[unc]
302/// impl UncRngExample {
303///     pub fn increment(&mut self) {
304///         let mut rng = Rng::new(&env::random_seed());
305///         let value = rng.rand_range_i32(0, 20);
306///         self.val += value;
307///     }
308///     pub fn get_value(&mut self) -> i32 {
309///         self.val
310///     }
311/// }
312/// ```
313/// More info in [documentation](https://docs.unc.org/develop/contracts/security/random)
314pub fn random_seed_array() -> [u8; 32] {
315    //* SAFETY: random_seed syscall will always generate 32 bytes inside of the atomic op register
316    //*         so the read will have a sufficient buffer of 32, and can transmute from uninit
317    //*         because all bytes are filled. This assumes a valid random_seed implementation.
318    unsafe {
319        sys::random_seed(ATOMIC_OP_REGISTER);
320        read_register_fixed_32(ATOMIC_OP_REGISTER)
321    }
322}
323
324/// Hashes the random sequence of bytes using sha256.
325///
326/// # Examples
327///
328/// ```
329/// use unc_sdk::env::sha256;
330/// use hex;
331///
332/// assert_eq!(
333///     sha256(b"The phrase that will be hashed"),
334///     hex::decode("7fc38bc74a0d0e592d2b8381839adc2649007d5bca11f92eeddef78681b4e3a3").expect("Decoding failed")
335/// );
336/// ```
337pub fn sha256(value: &[u8]) -> Vec<u8> {
338    sha256_array(value).to_vec()
339}
340
341/// Hashes the random sequence of bytes using keccak256.
342pub fn keccak256(value: &[u8]) -> Vec<u8> {
343    keccak256_array(value).to_vec()
344}
345
346/// Hashes the random sequence of bytes using keccak512.
347pub fn keccak512(value: &[u8]) -> Vec<u8> {
348    keccak512_array(value).to_vec()
349}
350
351/// Hashes the bytes using the SHA-256 hash function. This returns a 32 byte hash.
352///
353/// # Examples
354///
355/// ```
356/// use unc_sdk::env::sha256_array;
357/// use hex;
358///
359/// assert_eq!(
360///     &sha256_array(b"The phrase that will be hashed"),
361///     hex::decode("7fc38bc74a0d0e592d2b8381839adc2649007d5bca11f92eeddef78681b4e3a3")
362///         .expect("Decoding failed")
363///         .as_slice()
364/// );
365/// ```
366pub fn sha256_array(value: &[u8]) -> [u8; 32] {
367    //* SAFETY: sha256 syscall will always generate 32 bytes inside of the atomic op register
368    //*         so the read will have a sufficient buffer of 32, and can transmute from uninit
369    //*         because all bytes are filled. This assumes a valid sha256 implementation.
370    unsafe {
371        sys::sha256(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
372        read_register_fixed_32(ATOMIC_OP_REGISTER)
373    }
374}
375
376/// Hashes the bytes using the Keccak-256 hash function. This returns a 32 byte hash.
377pub fn keccak256_array(value: &[u8]) -> [u8; 32] {
378    //* SAFETY: keccak256 syscall will always generate 32 bytes inside of the atomic op register
379    //*         so the read will have a sufficient buffer of 32, and can transmute from uninit
380    //*         because all bytes are filled. This assumes a valid keccak256 implementation.
381    unsafe {
382        sys::keccak256(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
383        read_register_fixed_32(ATOMIC_OP_REGISTER)
384    }
385}
386
387/// Hashes the bytes using the Keccak-512 hash function. This returns a 64 byte hash.
388pub fn keccak512_array(value: &[u8]) -> [u8; 64] {
389    //* SAFETY: keccak512 syscall will always generate 64 bytes inside of the atomic op register
390    //*         so the read will have a sufficient buffer of 64, and can transmute from uninit
391    //*         because all bytes are filled. This assumes a valid keccak512 implementation.
392    unsafe {
393        sys::keccak512(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
394        read_register_fixed_64(ATOMIC_OP_REGISTER)
395    }
396}
397
398/// Hashes the bytes using the RIPEMD-160 hash function. This returns a 20 byte hash.
399pub fn ripemd160_array(value: &[u8]) -> [u8; 20] {
400    //* SAFETY: ripemd160 syscall will always generate 20 bytes inside of the atomic op register
401    //*         so the read will have a sufficient buffer of 20, and can transmute from uninit
402    //*         because all bytes are filled. This assumes a valid ripemd160 implementation.
403    unsafe {
404        sys::ripemd160(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
405        read_register_fixed_20(ATOMIC_OP_REGISTER)
406    }
407}
408
409/// Recovers an ECDSA signer address from a 32-byte message `hash` and a corresponding `signature`
410/// along with `v` recovery byte.
411///
412/// Takes in an additional flag to check for malleability of the signature
413/// which is generally only ideal for transactions.
414///
415/// Returns 64 bytes representing the public key if the recovery was successful.
416#[cfg(feature = "unstable")]
417pub fn ecrecover(
418    hash: &[u8],
419    signature: &[u8],
420    v: u8,
421    malleability_flag: bool,
422) -> Option<[u8; 64]> {
423    unsafe {
424        let return_code = sys::ecrecover(
425            hash.len() as _,
426            hash.as_ptr() as _,
427            signature.len() as _,
428            signature.as_ptr() as _,
429            v as u64,
430            malleability_flag as u64,
431            ATOMIC_OP_REGISTER,
432        );
433        if return_code == 0 {
434            None
435        } else {
436            Some(read_register_fixed_64(ATOMIC_OP_REGISTER))
437        }
438    }
439}
440
441/// Verifies signature of message using provided ED25519 Public Key
442pub fn ed25519_verify(signature: &[u8; 64], message: &[u8], public_key: &[u8; 32]) -> bool {
443    unsafe {
444        sys::ed25519_verify(
445            signature.len() as _,
446            signature.as_ptr() as _,
447            message.len() as _,
448            message.as_ptr() as _,
449            public_key.len() as _,
450            public_key.as_ptr() as _,
451        ) == 1
452    }
453}
454
455/// Compute alt_bn128 g1 multiexp.
456///
457/// `alt_bn128` is a specific curve from the Barreto-Naehrig(BN) family. It is particularly
458/// well-suited for ZK proofs.
459///
460/// See also: [EIP-196](https://eips.ethereum.org/EIPS/eip-196)
461pub fn alt_bn128_g1_multiexp(value: &[u8]) -> Vec<u8> {
462    unsafe {
463        sys::alt_bn128_g1_multiexp(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
464    };
465    read_register(ATOMIC_OP_REGISTER).expect(REGISTER_EXPECTED_ERR)
466}
467
468/// Compute alt_bn128 g1 sum.
469///
470/// `alt_bn128` is a specific curve from the Barreto-Naehrig(BN) family. It is particularly
471/// well-suited for ZK proofs.
472///
473/// See also: [EIP-196](https://eips.ethereum.org/EIPS/eip-196)
474pub fn alt_bn128_g1_sum(value: &[u8]) -> Vec<u8> {
475    unsafe {
476        sys::alt_bn128_g1_sum(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
477    };
478    read_register(ATOMIC_OP_REGISTER).expect(REGISTER_EXPECTED_ERR)
479}
480
481/// Compute pairing check
482///
483/// `alt_bn128` is a specific curve from the Barreto-Naehrig(BN) family. It is particularly
484/// well-suited for ZK proofs.
485///
486/// See also: [EIP-197](https://eips.ethereum.org/EIPS/eip-197)
487pub fn alt_bn128_pairing_check(value: &[u8]) -> bool {
488    unsafe { sys::alt_bn128_pairing_check(value.len() as _, value.as_ptr() as _) == 1 }
489}
490
491// ################
492// # Promises API #
493// ################
494/// Creates a promise that will execute a method on account with given arguments and attaches
495/// the given amount and gas.
496pub fn promise_create(
497    account_id: AccountId,
498    function_name: &str,
499    arguments: &[u8],
500    amount: UncToken,
501    gas: Gas,
502) -> PromiseIndex {
503    let account_id = account_id.as_bytes();
504    unsafe {
505        PromiseIndex(sys::promise_create(
506            account_id.len() as _,
507            account_id.as_ptr() as _,
508            function_name.len() as _,
509            function_name.as_ptr() as _,
510            arguments.len() as _,
511            arguments.as_ptr() as _,
512            &amount.as_attounc() as *const u128 as _,
513            gas.as_gas(),
514        ))
515    }
516}
517
518/// Attaches the callback that is executed after promise pointed by `promise_idx` is complete.
519pub fn promise_then(
520    promise_idx: PromiseIndex,
521    account_id: AccountId,
522    function_name: &str,
523    arguments: &[u8],
524    amount: UncToken,
525    gas: Gas,
526) -> PromiseIndex {
527    let account_id = account_id.as_bytes();
528    unsafe {
529        PromiseIndex(sys::promise_then(
530            promise_idx.0,
531            account_id.len() as _,
532            account_id.as_ptr() as _,
533            function_name.len() as _,
534            function_name.as_ptr() as _,
535            arguments.len() as _,
536            arguments.as_ptr() as _,
537            &amount.as_attounc() as *const u128 as _,
538            gas.as_gas(),
539        ))
540    }
541}
542
543/// Creates a new promise which completes when time all promises passed as arguments complete.
544pub fn promise_and(promise_indices: &[PromiseIndex]) -> PromiseIndex {
545    let mut data = vec![0u8; size_of_val(promise_indices)];
546    for i in 0..promise_indices.len() {
547        data[i * size_of::<PromiseIndex>()..(i + 1) * size_of::<PromiseIndex>()]
548            .copy_from_slice(&promise_indices[i].0.to_le_bytes());
549    }
550    unsafe { PromiseIndex(sys::promise_and(data.as_ptr() as _, promise_indices.len() as _)) }
551}
552
553pub fn promise_batch_create(account_id: &AccountId) -> PromiseIndex {
554    let account_id: &str = account_id.as_ref();
555    unsafe {
556        PromiseIndex(sys::promise_batch_create(account_id.len() as _, account_id.as_ptr() as _))
557    }
558}
559
560pub fn promise_batch_then(promise_index: PromiseIndex, account_id: &AccountId) -> PromiseIndex {
561    let account_id: &str = account_id.as_ref();
562    unsafe {
563        PromiseIndex(sys::promise_batch_then(
564            promise_index.0,
565            account_id.len() as _,
566            account_id.as_ptr() as _,
567        ))
568    }
569}
570
571pub fn promise_batch_action_create_account(promise_index: PromiseIndex) {
572    unsafe { sys::promise_batch_action_create_account(promise_index.0) }
573}
574
575pub fn promise_batch_action_deploy_contract(promise_index: PromiseIndex, code: &[u8]) {
576    unsafe {
577        sys::promise_batch_action_deploy_contract(
578            promise_index.0,
579            code.len() as _,
580            code.as_ptr() as _,
581        )
582    }
583}
584
585pub fn promise_batch_action_function_call(
586    promise_index: PromiseIndex,
587    function_name: &str,
588    arguments: &[u8],
589    amount: UncToken,
590    gas: Gas,
591) {
592    unsafe {
593        sys::promise_batch_action_function_call(
594            promise_index.0,
595            function_name.len() as _,
596            function_name.as_ptr() as _,
597            arguments.len() as _,
598            arguments.as_ptr() as _,
599            &amount.as_attounc() as *const u128 as _,
600            gas.as_gas(),
601        )
602    }
603}
604
605pub fn promise_batch_action_function_call_weight(
606    promise_index: PromiseIndex,
607    function_name: &str,
608    arguments: &[u8],
609    amount: UncToken,
610    gas: Gas,
611    weight: GasWeight,
612) {
613    unsafe {
614        sys::promise_batch_action_function_call_weight(
615            promise_index.0,
616            function_name.len() as _,
617            function_name.as_ptr() as _,
618            arguments.len() as _,
619            arguments.as_ptr() as _,
620            &amount.as_attounc() as *const u128 as _,
621            gas.as_gas(),
622            weight.0,
623        )
624    }
625}
626
627pub fn promise_batch_action_transfer(promise_index: PromiseIndex, amount: UncToken) {
628    unsafe {
629        sys::promise_batch_action_transfer(
630            promise_index.0,
631            &amount.as_attounc() as *const u128 as _,
632        )
633    }
634}
635
636pub fn promise_batch_action_stake(
637    promise_index: PromiseIndex,
638    amount: UncToken,
639    public_key: &PublicKey,
640) {
641    unsafe {
642        sys::promise_batch_action_stake(
643            promise_index.0,
644            &amount.as_attounc() as *const u128 as _,
645            public_key.as_bytes().len() as _,
646            public_key.as_bytes().as_ptr() as _,
647        )
648    }
649}
650pub fn promise_batch_action_add_key_with_full_access(
651    promise_index: PromiseIndex,
652    public_key: &PublicKey,
653    nonce: u64,
654) {
655    unsafe {
656        sys::promise_batch_action_add_key_with_full_access(
657            promise_index.0,
658            public_key.as_bytes().len() as _,
659            public_key.as_bytes().as_ptr() as _,
660            nonce,
661        )
662    }
663}
664
665/// This is a short lived function while we migrate between the Balance and the allowance type
666pub(crate) fn migrate_to_allowance(allowance: UncToken) -> Allowance {
667    Allowance::limited(allowance).unwrap_or(Allowance::Unlimited)
668}
669
670#[deprecated(since = "2.0.0", note = "Use add_access_key_allowance instead")]
671pub fn promise_batch_action_add_key_with_function_call(
672    promise_index: PromiseIndex,
673    public_key: &PublicKey,
674    nonce: u64,
675    allowance: UncToken,
676    receiver_id: &AccountId,
677    function_names: &str,
678) {
679    let allowance = migrate_to_allowance(allowance);
680    promise_batch_action_add_key_allowance_with_function_call(
681        promise_index,
682        public_key,
683        nonce,
684        allowance,
685        receiver_id,
686        function_names,
687    )
688}
689
690pub fn promise_batch_action_add_key_allowance_with_function_call(
691    promise_index: PromiseIndex,
692    public_key: &PublicKey,
693    nonce: u64,
694    allowance: Allowance,
695    receiver_id: &AccountId,
696    function_names: &str,
697) {
698    let receiver_id: &str = receiver_id.as_ref();
699    let allowance = match allowance {
700        Allowance::Limited(x) => x.get(),
701        Allowance::Unlimited => 0,
702    };
703    unsafe {
704        sys::promise_batch_action_add_key_with_function_call(
705            promise_index.0,
706            public_key.as_bytes().len() as _,
707            public_key.as_bytes().as_ptr() as _,
708            nonce,
709            &allowance as *const u128 as _,
710            receiver_id.len() as _,
711            receiver_id.as_ptr() as _,
712            function_names.len() as _,
713            function_names.as_ptr() as _,
714        )
715    }
716}
717pub fn promise_batch_action_delete_key(promise_index: PromiseIndex, public_key: &PublicKey) {
718    unsafe {
719        sys::promise_batch_action_delete_key(
720            promise_index.0,
721            public_key.as_bytes().len() as _,
722            public_key.as_bytes().as_ptr() as _,
723        )
724    }
725}
726
727pub fn promise_batch_action_delete_account(
728    promise_index: PromiseIndex,
729    beneficiary_id: &AccountId,
730) {
731    let beneficiary_id: &str = beneficiary_id.as_ref();
732    unsafe {
733        sys::promise_batch_action_delete_account(
734            promise_index.0,
735            beneficiary_id.len() as _,
736            beneficiary_id.as_ptr() as _,
737        )
738    }
739}
740
741/// If the current function is invoked by a callback we can access the execution results of the
742/// promises that caused the callback. This function returns the number of complete and
743/// incomplete callbacks.
744pub fn promise_results_count() -> u64 {
745    unsafe { sys::promise_results_count() }
746}
747/// If the current function is invoked by a callback we can access the execution results of the
748/// promises that caused the callback.
749pub fn promise_result(result_idx: u64) -> PromiseResult {
750    match promise_result_internal(result_idx) {
751        Ok(()) => {
752            let data = expect_register(read_register(ATOMIC_OP_REGISTER));
753            PromiseResult::Successful(data)
754        }
755        Err(PromiseError::Failed) => PromiseResult::Failed,
756    }
757}
758
759pub(crate) fn promise_result_internal(result_idx: u64) -> Result<(), PromiseError> {
760    match unsafe { sys::promise_result(result_idx, ATOMIC_OP_REGISTER) } {
761        1 => Ok(()),
762        2 => Err(PromiseError::Failed),
763        _ => abort(),
764    }
765}
766/// Consider the execution result of promise under `promise_idx` as execution result of this
767/// function.
768pub fn promise_return(promise_idx: PromiseIndex) {
769    unsafe { sys::promise_return(promise_idx.0) }
770}
771
772/// Creates a promise that will execute a method on the current account with given arguments.
773/// Writes a resumption token (data id) to the specified register. The callback method will execute
774/// after promise_yield_resume is called with the data id OR enough blocks have passed. The timeout
775/// length is specified as a protocol-level parameter yield_timeout_length_in_blocks = 200.
776///
777/// The callback method will execute with a single promise input. Input will either be a payload
778/// provided by the user when calling promise_yield_resume, or a PromiseError in case of timeout.
779///
780/// Resumption tokens are specific to the local account; promise_yield_resume must be called from
781/// a method of the same contract.
782pub fn promise_yield_create(
783    function_name: &str,
784    arguments: &[u8],
785    gas: Gas,
786    weight: GasWeight,
787    register_id: u64,
788) -> PromiseIndex {
789    unsafe {
790        PromiseIndex(sys::promise_yield_create(
791            function_name.len() as _,
792            function_name.as_ptr() as _,
793            arguments.len() as _,
794            arguments.as_ptr() as _,
795            gas.as_gas(),
796            weight.0,
797            register_id as _,
798        ))
799    }
800}
801
802/// Accepts a resumption token `data_id` created by promise_yield_create on the local account.
803/// `data` is a payload to be passed to the callback method as a promise input. Returns false if
804/// no promise yield with the specified `data_id` is found. Returns true otherwise, guaranteeing
805/// that the callback method will be executed with a user-provided payload.
806///
807/// If promise_yield_resume is called multiple times with the same `data_id`, it is possible to get
808/// back multiple 'true' results. The payload from the first successful call is passed to the
809/// callback.
810pub fn promise_yield_resume(data_id: &CryptoHash, data: &[u8]) -> bool {
811    unsafe {
812        sys::promise_yield_resume(
813            data_id.len() as _,
814            data_id.as_ptr() as _,
815            data.len() as _,
816            data.as_ptr() as _,
817        ) != 0
818    }
819}
820
821// ###############
822// # Validator API #
823// ###############
824
825/// For a given account return its current stake. If the account is not a validator, returns 0.
826pub fn validator_stake(account_id: &AccountId) -> UncToken {
827    let account_id: &str = account_id.as_ref();
828    let data = [0u8; size_of::<UncToken>()];
829    unsafe {
830        sys::validator_stake(account_id.len() as _, account_id.as_ptr() as _, data.as_ptr() as u64)
831    };
832    UncToken::from_attounc(u128::from_le_bytes(data))
833}
834
835/// Returns the total stake of validators in the current epoch.
836pub fn validator_total_stake() -> UncToken {
837    let data = [0u8; size_of::<UncToken>()];
838    unsafe { sys::validator_total_stake(data.as_ptr() as u64) };
839    UncToken::from_attounc(u128::from_le_bytes(data))
840}
841
842// #####################
843// # Miscellaneous API #
844// #####################
845/// Sets the blob of data as the return value of the contract.
846pub fn value_return(value: &[u8]) {
847    unsafe { sys::value_return(value.len() as _, value.as_ptr() as _) }
848}
849/// Terminates the execution of the program with the UTF-8 encoded message.
850/// [`panic_str`] should be used as the bytes are required to be UTF-8
851#[deprecated(since = "2.0.0", note = "Use env::panic_str to panic with a message.")]
852pub fn panic(message: &[u8]) -> ! {
853    unsafe { sys::panic_utf8(message.len() as _, message.as_ptr() as _) }
854}
855
856/// Terminates the execution of the program with the UTF-8 encoded message.
857pub fn panic_str(message: &str) -> ! {
858    unsafe { sys::panic_utf8(message.len() as _, message.as_ptr() as _) }
859}
860
861/// Aborts the current contract execution without a custom message.
862/// To include a message, use [`panic_str`].
863pub fn abort() -> ! {
864    // Use wasm32 unreachable call to avoid including the `panic` external function in Wasm.
865    #[cfg(target_arch = "wasm32")]
866    //* This was stabilized recently (~ >1.51), so ignore warnings but don't enforce higher msrv
867    #[allow(unused_unsafe)]
868    unsafe {
869        core::arch::wasm32::unreachable()
870    }
871    #[cfg(not(target_arch = "wasm32"))]
872    unsafe {
873        sys::panic()
874    }
875}
876
877/// Logs the string message message. This message is stored on chain.
878pub fn log_str(message: &str) {
879    #[cfg(all(debug_assertions, not(target_arch = "wasm32")))]
880    eprintln!("{}", message);
881
882    unsafe { sys::log_utf8(message.len() as _, message.as_ptr() as _) }
883}
884
885/// Log the UTF-8 encodable message.
886#[deprecated(since = "2.0.0", note = "Use env::log_str for logging messages.")]
887pub fn log(message: &[u8]) {
888    #[cfg(all(debug_assertions, not(target_arch = "wasm32")))]
889    eprintln!("{}", String::from_utf8_lossy(message));
890
891    unsafe { sys::log_utf8(message.len() as _, message.as_ptr() as _) }
892}
893
894// ###############
895// # Storage API #
896// ###############
897/// Writes key-value into storage.
898/// If another key-value existed in the storage with the same key it returns `true`, otherwise `false`.
899///
900/// # Examples
901///
902/// ```
903/// use unc_sdk::env::{storage_write, storage_read};
904///
905/// assert!(!storage_write(b"key", b"value"));
906/// assert!(storage_write(b"key", b"another_value"));
907/// assert_eq!(storage_read(b"key").unwrap(), b"another_value");
908/// ```
909pub fn storage_write(key: &[u8], value: &[u8]) -> bool {
910    match unsafe {
911        sys::storage_write(
912            key.len() as _,
913            key.as_ptr() as _,
914            value.len() as _,
915            value.as_ptr() as _,
916            EVICTED_REGISTER,
917        )
918    } {
919        0 => false,
920        1 => true,
921        _ => abort(),
922    }
923}
924/// Reads the value stored under the given key.
925///
926/// # Examples
927///
928/// ```
929/// use unc_sdk::env::{storage_write, storage_read};
930///
931/// assert!(storage_read(b"key").is_none());
932/// storage_write(b"key", b"value");
933/// assert_eq!(storage_read(b"key").unwrap(), b"value");
934/// ```
935pub fn storage_read(key: &[u8]) -> Option<Vec<u8>> {
936    match unsafe { sys::storage_read(key.len() as _, key.as_ptr() as _, ATOMIC_OP_REGISTER) } {
937        0 => None,
938        1 => Some(expect_register(read_register(ATOMIC_OP_REGISTER))),
939        _ => abort(),
940    }
941}
942/// Removes the value stored under the given key.
943/// If key-value existed returns `true`, otherwise `false`.
944pub fn storage_remove(key: &[u8]) -> bool {
945    match unsafe { sys::storage_remove(key.len() as _, key.as_ptr() as _, EVICTED_REGISTER) } {
946        0 => false,
947        1 => true,
948        _ => abort(),
949    }
950}
951/// Reads the most recent value that was evicted with `storage_write` or `storage_remove` command.
952pub fn storage_get_evicted() -> Option<Vec<u8>> {
953    read_register(EVICTED_REGISTER)
954}
955/// Checks if there is a key-value in the storage.
956pub fn storage_has_key(key: &[u8]) -> bool {
957    match unsafe { sys::storage_has_key(key.len() as _, key.as_ptr() as _) } {
958        0 => false,
959        1 => true,
960        _ => abort(),
961    }
962}
963
964// ############################################
965// # Saving and loading of the contract state #
966// ############################################
967/// Load the state of the given object.
968pub fn state_read<T: borsh::BorshDeserialize>() -> Option<T> {
969    storage_read(STATE_KEY)
970        .map(|data| T::try_from_slice(&data).expect("Cannot deserialize the contract state."))
971}
972
973pub fn state_write<T: borsh::BorshSerialize>(state: &T) {
974    let data = borsh::to_vec(state).expect("Cannot serialize the contract state.");
975    storage_write(STATE_KEY, &data);
976}
977
978/// Returns `true` if the contract state exists and `false` otherwise.
979pub fn state_exists() -> bool {
980    storage_has_key(STATE_KEY)
981}
982
983// #####################################
984// # Parameters exposed by the runtime #
985// #####################################
986
987/// Price per 1 byte of storage from mainnet genesis config.
988/// TODO: will be using the host function when it will be available.
989
990pub fn storage_byte_cost() -> UncToken {
991    UncToken::from_attounc(10_000_000_000_000_000_000u128)
992}
993
994// ##################
995// # Helper methods #
996// ##################
997
998/// Returns `true` if the given account ID is valid and `false` otherwise.
999pub fn is_valid_account_id(account_id: &[u8]) -> bool {
1000    if (account_id.len() as u64) < MIN_ACCOUNT_ID_LEN
1001        || (account_id.len() as u64) > MAX_ACCOUNT_ID_LEN
1002    {
1003        return false;
1004    }
1005
1006    // NOTE: We don't want to use Regex here, because it requires extra time to compile it.
1007    // The valid account ID regex is /^(([a-z\d]+[-_])*[a-z\d]+\.)*([a-z\d]+[-_])*[a-z\d]+$/
1008    // Instead the implementation is based on the previous character checks.
1009
1010    // We can safely assume that last char was a separator.
1011    let mut last_char_is_separator = true;
1012
1013    for c in account_id {
1014        let current_char_is_separator = match *c {
1015            b'a'..=b'z' | b'0'..=b'9' => false,
1016            b'-' | b'_' | b'.' => true,
1017            _ => return false,
1018        };
1019        if current_char_is_separator && last_char_is_separator {
1020            return false;
1021        }
1022        last_char_is_separator = current_char_is_separator;
1023    }
1024    // The account can't end as separator.
1025    !last_char_is_separator
1026}
1027
1028#[cfg(test)]
1029mod tests {
1030    use super::*;
1031
1032    #[test]
1033    fn test_is_valid_account_id_strings() {
1034        // Valid
1035        for account_id in &[
1036            "aa",
1037            "a-a",
1038            "a-aa",
1039            "100",
1040            "0o",
1041            "com",
1042            "unc",
1043            "bowen",
1044            "b-o_w_e-n",
1045            "b.owen",
1046            "bro.wen",
1047            "a.ha",
1048            "a.b-a.ra",
1049            "system",
1050            "over.9000",
1051            "google.com",
1052            "wick.cheapaccounts.unc",
1053            "0o0ooo00oo00o",
1054            "alex-skidanov",
1055            "10-4.8-2",
1056            "b-o_w_e-n",
1057            "no_lols",
1058            "0123456789012345678901234567890123456789012345678901234567890123",
1059            // Valid, but can't be created
1060            "unc.a",
1061            "a.a",
1062        ] {
1063            assert!(
1064                is_valid_account_id(account_id.as_ref()),
1065                "Valid account id {:?} marked invalid",
1066                account_id
1067            );
1068        }
1069
1070        // Invalid
1071        for account_id in &[
1072            "",
1073            "a",
1074            "A",
1075            "Abc",
1076            "-unc",
1077            "unc-",
1078            "-unc-",
1079            "unc.",
1080            ".unc",
1081            "unc@",
1082            "@unc",
1083            "неар",
1084            "@@@@@",
1085            "0__0",
1086            "0_-_0",
1087            "0_-_0",
1088            "..",
1089            "a..unc",
1090            "nEar",
1091            "_bowen",
1092            "hello world",
1093            "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz",
1094            "01234567890123456789012345678901234567890123456789012345678901234",
1095            // `@` separators are banned now
1096            "some-complex-address@gmail.com",
1097            "sub.buy_d1gitz@atata@b0-rg.c_0_m",
1098        ] {
1099            assert!(
1100                !is_valid_account_id(account_id.as_ref()),
1101                "Invalid account id {:?} marked valid",
1102                account_id
1103            );
1104        }
1105    }
1106
1107    #[test]
1108    fn test_is_valid_account_id_binary() {
1109        assert!(!is_valid_account_id(&[]));
1110        assert!(!is_valid_account_id(&[0]));
1111        assert!(!is_valid_account_id(&[0, 1]));
1112        assert!(!is_valid_account_id(&[0, 1, 2]));
1113        assert!(is_valid_account_id(b"unc"));
1114    }
1115
1116    #[cfg(not(target_arch = "wasm32"))]
1117    #[test]
1118    fn hash_smoke_tests() {
1119        assert_eq!(
1120            &super::sha256_array(b"some value"),
1121            hex::decode("ab3d07f3169ccbd0ed6c4b45de21519f9f938c72d24124998aab949ce83bb51b")
1122                .unwrap()
1123                .as_slice()
1124        );
1125
1126        assert_eq!(
1127            &super::keccak256_array(b"some value"),
1128            hex::decode("f928dfb5fc72b3bbfb9a5ccb0ee9843b27b4ac1ebc25a6f6f783e23ebd47ef1f")
1129                .unwrap()
1130                .as_slice()
1131        );
1132
1133        assert_eq!(
1134            &super::keccak512_array(b"some value"),
1135            hex::decode("3e38d140a85123374ee63ec208973aa39b87349d17ccac948a2493e18b18b5913220cd174b4f511aa97977009e16be485fc94f5e2743cb9bb0579d35ab410583")
1136                .unwrap()
1137                .as_slice()
1138        );
1139
1140        assert_eq!(
1141            &super::ripemd160_array(b"some value"),
1142            hex::decode("09f025fed704e1ecac8f88b2bda3e56876da03ac").unwrap().as_slice()
1143        );
1144    }
1145
1146    #[cfg(not(target_arch = "wasm32"))]
1147    #[test]
1148    fn random_seed_smoke_test() {
1149        crate::testing_env!(crate::test_utils::VMContextBuilder::new()
1150            .random_seed([8; 32])
1151            .build());
1152
1153        assert_eq!(super::random_seed(), [8; 32]);
1154    }
1155
1156    #[cfg(not(target_arch = "wasm32"))]
1157    #[cfg(feature = "unstable")]
1158    #[test]
1159    fn test_ecrecover() {
1160        use crate::test_utils::test_env;
1161        use hex::FromHex;
1162        use serde::de::Error;
1163        use serde::{Deserialize, Deserializer};
1164        use serde_json::from_slice;
1165        use std::fmt::Display;
1166
1167        #[derive(Deserialize)]
1168        struct EcrecoverTest {
1169            #[serde(with = "hex::serde")]
1170            m: [u8; 32],
1171            v: u8,
1172            #[serde(with = "hex::serde")]
1173            sig: [u8; 64],
1174            mc: bool,
1175            #[serde(deserialize_with = "deserialize_option_hex")]
1176            res: Option<[u8; 64]>,
1177        }
1178
1179        fn deserialize_option_hex<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
1180        where
1181            D: Deserializer<'de>,
1182            T: FromHex,
1183            <T as FromHex>::Error: Display,
1184        {
1185            Deserialize::deserialize(deserializer)
1186                .map(|v: Option<&str>| v.map(FromHex::from_hex).transpose().map_err(Error::custom))
1187                .and_then(|v| v)
1188        }
1189
1190        test_env::setup_free();
1191        for EcrecoverTest { m, v, sig, mc, res } in
1192            from_slice::<'_, Vec<_>>(include_bytes!("../../tests/ecrecover-tests.json")).unwrap()
1193        {
1194            assert_eq!(super::ecrecover(&m, &sig, v, mc), res);
1195        }
1196    }
1197
1198    #[cfg(not(target_arch = "wasm32"))]
1199    #[test]
1200    fn signer_public_key() {
1201        let key: PublicKey =
1202            "ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp".parse().unwrap();
1203
1204        crate::testing_env!(crate::test_utils::VMContextBuilder::new()
1205            .signer_account_pk(key.clone())
1206            .build());
1207        assert_eq!(super::signer_account_pk(), key);
1208    }
1209
1210    #[test]
1211    fn ed25519_verify() {
1212        const SIGNATURE: [u8; 64] = [
1213            145, 193, 203, 18, 114, 227, 14, 117, 33, 213, 121, 66, 130, 14, 25, 4, 36, 120, 46,
1214            142, 226, 215, 7, 66, 122, 112, 97, 30, 249, 135, 61, 165, 221, 249, 252, 23, 105, 40,
1215            56, 70, 31, 152, 236, 141, 154, 122, 207, 20, 75, 118, 79, 90, 168, 6, 221, 122, 213,
1216            29, 126, 196, 216, 104, 191, 6,
1217        ];
1218
1219        const BAD_SIGNATURE: [u8; 64] = [1; 64];
1220
1221        // create a forged signature with the `s` scalar not properly reduced
1222        // https://docs.rs/ed25519/latest/src/ed25519/lib.rs.html#302
1223        const FORGED_SIGNATURE: [u8; 64] = {
1224            let mut sig = SIGNATURE;
1225            sig[63] = 0b1110_0001;
1226            sig
1227        };
1228
1229        const PUBLIC_KEY: [u8; 32] = [
1230            32, 122, 6, 120, 146, 130, 30, 37, 215, 112, 241, 251, 160, 196, 124, 17, 255, 75, 129,
1231            62, 84, 22, 46, 206, 158, 184, 57, 224, 118, 35, 26, 182,
1232        ];
1233
1234        // create a forged public key to force a PointDecompressionError
1235        // https://docs.rs/ed25519-dalek/latest/src/ed25519_dalek/public.rs.html#142
1236        const FORGED_PUBLIC_KEY: [u8; 32] = {
1237            let mut key = PUBLIC_KEY;
1238            key[31] = 0b1110_0001;
1239            key
1240        };
1241
1242        // 32 bytes message
1243        const MESSAGE: [u8; 32] = [
1244            107, 97, 106, 100, 108, 102, 107, 106, 97, 108, 107, 102, 106, 97, 107, 108, 102, 106,
1245            100, 107, 108, 97, 100, 106, 102, 107, 108, 106, 97, 100, 115, 107,
1246        ];
1247
1248        assert!(super::ed25519_verify(&SIGNATURE, &MESSAGE, &PUBLIC_KEY));
1249        assert!(!super::ed25519_verify(&BAD_SIGNATURE, &MESSAGE, &FORGED_PUBLIC_KEY));
1250        assert!(!super::ed25519_verify(&SIGNATURE, &MESSAGE, &FORGED_PUBLIC_KEY));
1251        assert!(!super::ed25519_verify(&FORGED_SIGNATURE, &MESSAGE, &PUBLIC_KEY));
1252    }
1253
1254    #[test]
1255    pub fn alt_bn128_g1_multiexp() {
1256        // Originated from https://github.com/unc/unccore/blob/8cd095ffc98a6507ed2d2a8982a6a3e42ebc1b62/runtime/unc-test-contracts/estimator-contract/src/lib.rs#L557-L720
1257        let buffer = [
1258            16, 238, 91, 161, 241, 22, 172, 158, 138, 252, 202, 212, 136, 37, 110, 231, 118, 220,
1259            8, 45, 14, 153, 125, 217, 227, 87, 238, 238, 31, 138, 226, 8, 238, 185, 12, 155, 93,
1260            126, 144, 248, 200, 177, 46, 245, 40, 162, 169, 80, 150, 211, 157, 13, 10, 36, 44, 232,
1261            173, 32, 32, 115, 123, 2, 9, 47, 190, 148, 181, 91, 69, 6, 83, 40, 65, 222, 251, 70,
1262            81, 73, 60, 142, 130, 217, 176, 20, 69, 75, 40, 167, 41, 180, 244, 5, 142, 215, 135,
1263            35,
1264        ];
1265
1266        assert_eq!(
1267            super::alt_bn128_g1_multiexp(&buffer),
1268            vec![
1269                150, 94, 159, 52, 239, 226, 181, 150, 77, 86, 90, 186, 102, 219, 243, 204, 36, 128,
1270                164, 209, 106, 6, 62, 124, 235, 104, 223, 195, 30, 204, 42, 20, 13, 158, 14, 197,
1271                133, 73, 43, 171, 28, 68, 82, 116, 244, 164, 36, 251, 244, 8, 234, 40, 118, 55,
1272                216, 187, 242, 39, 213, 160, 192, 184, 28, 23
1273            ]
1274        );
1275    }
1276
1277    #[test]
1278    pub fn alt_bn128_g1_sum() {
1279        // Originated from https://github.com/unc/unccore/blob/8cd095ffc98a6507ed2d2a8982a6a3e42ebc1b62/runtime/unc-test-contracts/estimator-contract/src/lib.rs#L557-L720
1280        let buffer = [
1281            0, 11, 49, 94, 29, 152, 111, 116, 138, 248, 2, 184, 8, 159, 80, 169, 45, 149, 48, 32,
1282            49, 37, 6, 133, 105, 171, 194, 120, 44, 195, 17, 180, 35, 137, 154, 4, 192, 211, 244,
1283            93, 200, 2, 44, 0, 64, 26, 108, 139, 147, 88, 235, 242, 23, 253, 52, 110, 236, 67, 99,
1284            176, 2, 186, 198, 228, 25,
1285        ];
1286
1287        assert_eq!(
1288            super::alt_bn128_g1_sum(&buffer),
1289            vec![
1290                11, 49, 94, 29, 152, 111, 116, 138, 248, 2, 184, 8, 159, 80, 169, 45, 149, 48, 32,
1291                49, 37, 6, 133, 105, 171, 194, 120, 44, 195, 17, 180, 35, 137, 154, 4, 192, 211,
1292                244, 93, 200, 2, 44, 0, 64, 26, 108, 139, 147, 88, 235, 242, 23, 253, 52, 110, 236,
1293                67, 99, 176, 2, 186, 198, 228, 25
1294            ]
1295        );
1296    }
1297
1298    #[test]
1299    pub fn alt_bn128_pairing_check() {
1300        // Taken from https://github.com/unc/unccore/blob/8cd095ffc98a6507ed2d2a8982a6a3e42ebc1b62/runtime/unc-vm-runner/src/logic/tests/alt_bn128.rs#L239-L250
1301        let valid_pair = [
1302            117, 10, 217, 99, 113, 78, 234, 67, 183, 90, 26, 58, 200, 86, 195, 123, 42, 184, 213,
1303            88, 224, 248, 18, 200, 108, 6, 181, 6, 28, 17, 99, 7, 36, 134, 53, 115, 192, 180, 3,
1304            113, 76, 227, 174, 147, 50, 174, 79, 74, 151, 195, 172, 10, 211, 210, 26, 92, 117, 246,
1305            65, 237, 168, 104, 16, 4, 1, 26, 3, 219, 6, 13, 193, 115, 77, 230, 27, 13, 242, 214,
1306            195, 9, 213, 99, 135, 12, 160, 202, 114, 135, 175, 42, 116, 172, 79, 234, 26, 41, 212,
1307            111, 192, 129, 124, 112, 57, 107, 38, 244, 230, 222, 240, 36, 65, 238, 133, 188, 19,
1308            43, 148, 59, 205, 40, 161, 179, 173, 228, 88, 169, 231, 29, 17, 67, 163, 51, 165, 187,
1309            101, 44, 250, 24, 68, 101, 92, 128, 203, 190, 51, 85, 9, 43, 58, 136, 68, 180, 92, 110,
1310            185, 168, 107, 129, 45, 30, 187, 22, 100, 17, 75, 93, 216, 125, 23, 212, 11, 186, 199,
1311            204, 1, 140, 133, 11, 82, 44, 65, 222, 20, 26, 48, 26, 132, 220, 25, 213, 93, 25, 79,
1312            176, 4, 149, 151, 243, 11, 131, 253, 233, 121, 38, 222, 15, 118, 117, 200, 214, 175,
1313            233, 130, 181, 193, 167, 255, 153, 169, 240, 207, 235, 28, 31, 83, 74, 69, 179, 6, 150,
1314            72, 67, 74, 166, 130, 83, 82, 115, 123, 111, 208, 221, 64, 43, 237, 213, 186, 235, 7,
1315            56, 251, 179, 95, 233, 159, 23, 109, 173, 85, 103, 8, 165, 235, 226, 218, 79, 72, 120,
1316            172, 251, 20, 83, 121, 201, 140, 98, 170, 246, 121, 218, 19, 115, 42, 135, 60, 239, 30,
1317            32, 49, 170, 171, 204, 196, 197, 160, 158, 168, 47, 23, 110, 139, 123, 222, 222, 245,
1318            98, 125, 208, 70, 39, 110, 186, 146, 254, 66, 185, 118, 3, 78, 32, 47, 179, 197, 93,
1319            79, 240, 204, 78, 236, 133, 213, 173, 117, 94, 63, 154, 68, 89, 236, 138, 0, 247, 242,
1320            212, 245, 33, 249, 0, 35, 246, 233, 0, 124, 86, 198, 162, 201, 54, 19, 26, 196, 75,
1321            254, 71, 70, 238, 51, 2, 23, 185, 152, 139, 134, 65, 107, 129, 114, 244, 47, 251, 240,
1322            80, 193, 23,
1323        ];
1324        assert!(super::alt_bn128_pairing_check(&valid_pair));
1325
1326        // Taken from https://github.com/unc/unccore/blob/8cd095ffc98a6507ed2d2a8982a6a3e42ebc1b62/runtime/unc-vm-runner/src/logic/tests/alt_bn128.rs#L254-L265
1327        let invalid_pair = [
1328            117, 10, 217, 99, 113, 78, 234, 67, 183, 90, 26, 58, 200, 86, 195, 123, 42, 184, 213,
1329            88, 224, 248, 18, 200, 108, 6, 181, 6, 28, 17, 99, 7, 36, 134, 53, 115, 192, 180, 3,
1330            113, 76, 227, 174, 147, 50, 174, 79, 74, 151, 195, 172, 10, 211, 210, 26, 92, 117, 246,
1331            65, 237, 168, 104, 16, 4, 1, 26, 3, 219, 6, 13, 193, 115, 77, 230, 27, 13, 242, 214,
1332            195, 9, 213, 99, 135, 12, 160, 202, 114, 135, 175, 42, 116, 172, 79, 234, 26, 41, 212,
1333            111, 192, 129, 124, 112, 57, 107, 38, 244, 230, 222, 240, 36, 65, 238, 133, 188, 19,
1334            43, 148, 59, 205, 40, 161, 179, 173, 228, 88, 169, 231, 29, 17, 67, 163, 51, 165, 187,
1335            101, 44, 250, 24, 68, 101, 92, 128, 203, 190, 51, 85, 9, 43, 58, 136, 68, 180, 92, 110,
1336            185, 168, 107, 129, 45, 30, 187, 22, 100, 17, 75, 93, 216, 125, 23, 212, 11, 186, 199,
1337            204, 1, 140, 133, 11, 82, 44, 65, 222, 20, 26, 48, 26, 132, 220, 25, 213, 93, 25, 117,
1338            10, 217, 99, 113, 78, 234, 67, 183, 90, 26, 58, 200, 86, 195, 123, 42, 184, 213, 88,
1339            224, 248, 18, 200, 108, 6, 181, 6, 28, 17, 99, 7, 36, 134, 53, 115, 192, 180, 3, 113,
1340            76, 227, 174, 147, 50, 174, 79, 74, 151, 195, 172, 10, 211, 210, 26, 92, 117, 246, 65,
1341            237, 168, 104, 16, 4, 109, 173, 85, 103, 8, 165, 235, 226, 218, 79, 72, 120, 172, 251,
1342            20, 83, 121, 201, 140, 98, 170, 246, 121, 218, 19, 115, 42, 135, 60, 239, 30, 32, 49,
1343            170, 171, 204, 196, 197, 160, 158, 168, 47, 23, 110, 139, 123, 222, 222, 245, 98, 125,
1344            208, 70, 39, 110, 186, 146, 254, 66, 185, 118, 3, 78, 32, 47, 179, 197, 93, 79, 240,
1345            204, 78, 236, 133, 213, 173, 117, 94, 63, 154, 68, 89, 236, 138, 0, 247, 242, 212, 245,
1346            33, 249, 0, 35, 246, 233, 0, 124, 86, 198, 162, 201, 54, 19, 26, 196, 75, 254, 71, 70,
1347            238, 51, 2, 23, 185, 152, 139, 134, 65, 107, 129, 114, 244, 47, 251, 240, 80, 193, 23,
1348        ];
1349
1350        assert!(!super::alt_bn128_pairing_check(&invalid_pair));
1351    }
1352}