In a Rust test, how can I check the state (account balance) of an account using NEAR protocol? - nearprotocol

In a Rust test, how can I check the state (account balance) of an account?
E.g. I have this helper function:
fn set_context(account_index: usize, is_view: bool, deposit: Amount) {
let context = VMContextBuilder::new()
.signer_account_id(accounts(account_index))
.is_view(is_view)
.attached_deposit(deposit)
.build();
testing_env!(context);
}
And then my test contains:
...
let mut contract = Contract::new();
set_context(1, false, near_string_to_yocto("0.3".to_string()));
let recipient = accounts(0);
let _matcher1_offer_result = contract.offer_matching_funds(&recipient);
set_context(2, false, near_string_to_yocto("0.1".to_string()));
let _matcher2_offer_result = contract.offer_matching_funds(&recipient);
// TODO: Assert that this (escrow) contract now contains the correct amount of funds. Assert that the matchers' account balances have decreased appropriately.
I haven't been able to find an example in any docs or repo.
E.g. https://docs.rs/near-sdk/latest/src/near_sdk/test_utils/context.rs.html#10-14

Can't directly comment on Vlad's post due to low reputation, but the method you'd need to get the account details such as account balance is the account.view_account() method. You can find all related account methods here as well: https://docs.rs/workspaces/0.4.0/workspaces/struct.Account.html
The Workspaces docs aren't good yet
Any feedback as to how we can improve the docs?

Given that the balance is changed by the NEAR Protocol and the contract method cannot just change the balance directly, the only thing contract developers can check in unit tests is whether there was some promise returned with the tokens transferred. The current balance in the unit-test environment is available through near_sdk::env::account_balance()
If there is a need to do end-to-end testing, I recommend using https://github.com/near/workspaces-rs or https://github.com/near/workspaces-js

Related

How to detect which network your contract is on

Is it possible to detect which network (testnet, mainnet etc..) your contract is in via, for example, env in Rust? I have a contract that will be deployed to both testnet and mainnet and I have logic that depends on the network.
There are a two things you can do in this case that I could think of.
You could store in the state of the contract which network it lives on and then pass that into the initialization function.
If you wanted to use env, you could right split env::current_account_id() and check for .testnet at the end of the account ID.
Note: This method won't work if your contract is deployed to an implicit account.
An example of the code is:
// Get this with env::current_account_id();
let str = "benji.testnet.fayyr.testnet".to_string();
// Get the split at the end of the string using `.testnet`
let split_check = str.rsplit_once(".testnet");
// Default network to mainnet
let mut network = "mainnet";
// If `.testnet` was found, make sure it was at the end of the account ID
if let Some(split) = split_check {
if split.1.len() == 0 {
network = "testnet";
}
}

Project reactor: repeat service call and collect response results until condition met

Greetings venerable SO community...
I come to everyone today in need of a reactive solution for a problem I've not yet encountered.
I would still consider myself a reactive neophyte at this point, and although I've been reading over "Hands On Reactive Programming in Spring" I've still got the boss looking over me and tapping his foot if you know what I mean, so I'm again hoping that some benevolent and brilliant soul might point me in the right direction for an implementation I'm presently tasked with.
Here's the situation:
I have to call an external service providing a list of transactions(containing transaction data) for a given date range.
In addition to the date range being passed in the request to the external service, there's also number of transactions per page, we'll call "N", and page number, we'll call "P."
So say for a certain date range there is a total of 23 transactions.
Then:
For N=10 and P=1 they will return 10 transactions, from 1-10
For N=10 and P=2 we’d get transactions 11-20.
For N=10 and P=3 we’d get transactions 21-23.
For N=10 and P=4 or higher no transactions would be returned.
For N=7 and P=3 we’d get transactions 15-21.
For N=30 and P=1 we’d get all 23 transactions and know that we have all of the transactions because the number returned is less than number requested.
(Please note, we have no idea how many transaction records in total will ultimately be returned.)
So what I'm after is some sort of reactive construct that can potentially repeatedly call the remote transaction list service, check if the total number returned is less than the total number requested, and if not, call again while saving up/accumulating all the records in another list, and then once we reach the end, send this other list of all the transactions back in a response to the service that invoked this code.
Does this make sense, or no?
I've been searching SO, and so far I found this article that seems somewhat applicable and promising using the "repeat" functionality, but I'm really not sure if this is the right path or not.
I also found this article which also seems like it might be relevant.
Again, and as always, any and all help/guidance here is immensely appreciated!
Greetings once again SO community.
I was finally able to come up with a solution for this problem thanks to help from a more experienced co-worker.
public Flux<TransactionListData> getTransactionList(String cardId, TransactionLookupCriteria lookupCriteria) {
return cardService.getByCardId(cardId)
.map(Card::getAccountId)
.flatMap(accountService::getAccount)
.flatMap(account -> fetchTransactions(account, lookupCriteria))
.flatMapMany(Flux::fromIterable)
.map(this::negateTransactionAmountIfNecessary)
.map(this::setTransactionApprovalFlag);
}
private Mono<List<TransactionListData>> fetchTransactions(Account account,
TransactionLookupCriteria lookupCriteria) {
final PageNumber pageNumber = new PageNumber();
return Flux.defer(() -> getTransactions(account, lookupCriteria, pageNumber))
.repeatWhen(transactions -> transactions.takeWhile(transactionCount -> transactionCount == TRANSACTIONS_REQUESTED_PER_PAGE))
.collectList();
}
private Flux<TransactionListData> getTransactions(Account account, TransactionLookupCriteria lookupCriteria, PageNumber pageNumber) {
return Mono.just(createGetTransactionListServiceRequestData(account, lookupCriteria, pageNumber.get()))
.flatMap(cartaClient::getTransactionList)
.map(GetTransactionListServiceResponse::getServiceResponseData)
.switchIfEmpty(Mono.defer(() -> Mono.error(new ServiceException("Transaction response data empty"))))
.doOnNext(x -> pageNumber.increment())
.flatMapIterable(GetTransactionListServiceResponseData::getTransactionList);
}
private class PageNumber {
int page = 1;
void increment() {
page++;
}
public int get() {
return page;
}
}

Substrate: How to validate the originator of unsigned extrinsics?

I need to be able to identify the source of an unsigned extrinsic for spam prevention purposes. Assume there is a set of known authorities from whom I am willing to accept an unsigned extrinsic. I want to check that the sender of the unsigned extrinsic is a member of this authority set (and that they are who they say they are).
From what I can tell there are a couple of different approaches and I would like to better understand the differences between each and the trade-offs involved.
Add a signature as a call parameter and define ValidateUnsigned.
This approach is used in the ImOnline pallet. Roughly speaking:
decl_module!(
// ...
fn my_unsigned_call(_origin,
args: MyArgs<T>,
authority: T::Authority,
signature: T::Signature) {
// Handle the call
todo!()
}
)
impl<T: Trait> frame_support::unsigned::ValidateUnsigned for Module<T> {
// ...
fn validate_unsigned(
_source: TransactionSource,
call: &Self::Call,
) -> TransactionValidity {
if let Call::my_unsigned_call(args, authority, signature) = call {
// Check the sender is in the approved authority set and verify sig
todo!();
}
}
}
Implement SignedExtension for some metadata associated with the pallet trait. This is touched upon in the docs and seems to be implemented in the TransactionPayment pallet. Implementation would be something like this:
struct SenderInfo<T> {
authority: T::Authority,
signature: T::Signature,
}
impl<T: Config + Send + Sync> SignedExtension for SenderInfo<T>
where
<T as frame_system::Config>::Call: IsSubType<Call<T>>,
{
// ...
fn validate_unsigned(
call: &Self::Call,
info: &DispatchInfoOf<Self::Call>,
len: usize
) -> TransactionValidity {
// validate self.authority and self.signature
}
}
This SignedExtension then needs to be aggregated into the SignedExtra of the runtime. (Right?)
I am tending towards using the second option since it seems cleaner: it doesn't require me to pollute my method signatures with extra information that is not even used in the method call. But would this mean that any transaction submitted to the runtime, signed or unsigned, would need to add this customised SignedExtra?
Are there any other considerations I should be aware of?
I'm working on a very similar thing.
I was able to do so with your approach 1.
Basically I do check two things there:
If payload was signed properly - When you think about it, this will tell you only about the user, but it doesn't check if a user is your authority user.
I do check if this account is on my authorities list
My working example is available here https://github.com/korzewski/jackblock/blob/master/pallets/jackblock/src/lib.rs#L401
Although, this is not perfect because I need to keep a second list of Authorities and add them manually.
Currently I'm trying to refactor it, so my authorities accounts are the same as my validators (Aura pallet). Still looking for a solution so maybe you know how to solve it? Basically how to reuse Aura pallet in my own pallet

What is the best way to test account balance changes in NEAR smart contracts?

I am trying to test that an account's NEAR balance increases and decreases.
env::account_balance() doesn’t seem to change even with an attached_deposit.
#[test]
fn takes_account_deposit() {
let mut context = get_context();
context.attached_deposit = 10000000000000000;
testing_env!(context.clone());
println!("Account balance before {}", env::account_balance());
let mut contract = Contract::default();
contract.take_deposit();
println!("Account balance after {}", env::account_balance());
}
Cross-contract calls in NEAR are asynchronous, so you need to setup a callback for the take_deposit (is my understanding correct that Contract is some other contract?). Learn more about promises and cross-contract calls in the doc

Functional programming and dependency inversion: how to abstract storage?

I'm trying to create a solution that has a lower-level library that will know that it needs to save and load data when certain commands are called, but the implementation of the save and load functions will be provided in a platform-specific project which references the lower-level library.
I have some models, such as:
type User = { UserID: UserID
Situations: SituationID list }
type Situation = { SituationID: SituationID }
And what I want to do is be able to define and call functions such as:
do saveUser ()
let user = loadUser (UserID 57)
Is there any way to define this cleanly in the functional idiom, preferably while avoiding mutable state (which shouldn't be necessary anyway)?
One way to do it might look something like this:
type IStorage = {
saveUser: User->unit;
loadUser: UserID->User }
module Storage =
// initialize save/load functions to "not yet implemented"
let mutable storage = {
saveUser = failwith "nyi";
loadUser = failwith "nyi" }
// ....elsewhere:
do Storage.storage = { a real implementation of IStorage }
do Storage.storage.saveUser ()
let user = Storage.storage.loadUser (UserID 57)
And there are variations on this, but all the ones I can think of involve some kind of uninitialized state. (In Xamarin, there's also DependencyService, but that is itself a dependency I would like to avoid.)
Is there any way to write code that calls a storage function, which hasn't been implemented yet, and then implement it, WITHOUT using mutable state?
(Note: this question is not about storage itself -- that's just the example I'm using. It's about how to inject functions without using unnecessary mutable state.)
Other answers here will perhaps educate you on how to implement the IO monad in F#, which is certainly an option. In F#, though, I'd often just compose functions with other functions. You don't have to define an 'interface' or any particular type in order to do this.
Develop your system from the Outside-In, and define your high-level functions by focusing on the behaviour they need to implement. Make them higher-order functions by passing in dependencies as arguments.
Need to query a data store? Pass in a loadUser argument. Need to save the user? Pass in a saveUser argument:
let myHighLevelFunction loadUser saveUser (userId) =
let user = loadUser (UserId userId)
match user with
| Some u ->
let u' = doSomethingInterestingWith u
saveUser u'
| None -> ()
The loadUser argument is inferred to be of type User -> User option, and saveUser as User -> unit, because doSomethingInterestingWith is a function of type User -> User.
You can now 'implement' loadUser and saveUser by writing functions that call into the lower-level library.
The typical reaction I get to this approach is: That'll require me to pass in too many arguments to my function!
Indeed, if that happens, consider if that isn't a smell that the function is attempting to do too much.
Since the Dependency Inversion Principle is mentioned in the title of this question, I'd like to point out that the SOLID principles work best if all of them are applied in concert. The Interface Segregation Principle says that interfaces should be as small as possible, and you don't get them smaller than when each 'interface' is a single function.
For a more detailed article describing this technique, you can read my Type-Driven Development article.
You can abstract storage behind interface IStorage. I think that was your intention.
type IStorage =
abstract member LoadUser : UserID -> User
abstract member SaveUser : User -> unit
module Storage =
let noStorage =
{ new IStorage with
member x.LoadUser _ -> failwith "not implemented"
member x.SaveUser _ -> failwith "not implemented"
}
In another part of your program you can have multiple storage implementations.
type MyStorage() =
interface IStorage with
member x.LoadUser uid -> ...
member x.SaveUser u -> ...
And after you have all your types defined you can decide which to use.
let storageSystem =
if today.IsShinyDay
then MyStorage() :> IStorage
else Storage.noStorage
let user = storageSystem.LoadUser userID

Resources