When to call getAssetRegistry to update assets (and the participants equivalent) - hyperledger

I'm able to write some simplistic smart contracts using my composer development environment but am confused about when to persist assets and participants into the registry.
I've read the docs on composer-runtime.AssetRegistry and the getAssetRegistry function to return an asset registry object and to perform updates but am still not clear which assets/partipants to update.
Here's an example (may not be fully working):
participant Trader identified by userID {
o String userID
o String firstName
o String lastName
}
participant Bank identified by bankID {
o String bankID
o String description
--> BankAccount[] accounts optional
}
asset BankAccount identified by accountID {
o String accountID
o Double balance
o AccountTrx[] transactions optional
--> Trader owner
}
transaction AccountTrx {
o Double amount
o String operation
--> BankAccount account
--> Trader party
}
If I write a transaction processor function to perform an account transaction (e.g. a withdrawal or deposit) such as this:
/**
* Perform a deposit or withdrawal from a bank account
* #param {org.acme.auctionnetwork.AccountTrx} transaction
* #transaction
*/
function execTrx(transaction) {
// initialize array of transactions if none exist
if(transaction.account.transactions == null) {
transaction.account.transactions = [];
}
// determine whether this is a deposit or withdrawal and execute accordingly
if(transaction.operation == 'W') {
transaction.account.balance -= transaction.amount;
} else if(transaction.operation == 'D') {
transaction.account.balance += transaction.amount;
}
// add the current transaction to the bank account's transaction history
transaction.account.transactions.push(transaction);
// update the registry (but which ones???)
return getAssetRegistry('org.acme.auctionnetwork.BankAccount')
.then(function(regBankAccount) {
return regBankAccount.update(transaction.account);
});
}
Am I right in assuming that only the BankAccount asset needs to be updated? (because the balance variable in the BankAccount asset has been updated)
Would I also need to update the Bank and Trader participants as well, since the Trader participant was part of the transaction AccountTrx and the Bank participant is linked to from the BankAccount asset? I don't see that anything has changed in either the Trader participant or BankAccount asset.

you shouldn't need to. The Asset account has a relationship yes, and you're calling the right AssetRegistry. One assumes you're passing in an amount in the first place when calling the txn using POST or otherwise. What do you see for an updated asset (BankAccount balance)? Why not use console.log() to check..

Related

How can accept other token in my Smart Contract?

The token is ERC721 by OpenZeppelin
I'm trying to add USDC payments to my Smart Contract, but I'm having problems.
This is my function to accept token.. but transfer its called by Smart Contract. Dont work...
function AcceptPayment(uint32 amount) public {
tokenUSDC.transfer(address(this), amount * priceCapsule);
bulkMint(_msgSender(), amount);
}
Allowance and approve its working fine, testing with Remix.
New try.. but get: Execution reverted on Remix
function AcceptPayment(uint32 amount) public {
bool success = tokenUSDC.transferFrom(msg.sender, address(this), amount * priceCapsule);
require(success, "Could not transfer token. Missing approval?");
bulkMint(_msgSender(), amount);
}
I can't find a solution to make the transfer from the Smart Contract itself.
The user needs to approve() your contract address to pull their tokens. This action needs to be called directly from the user address (on the token contract).
Then you can transferFrom() their address to yours.
function AcceptPayment(uint32 amount) public {
bool success = tokenUSDC.transferFrom(msg.sender, address(this), amount * priceCapsule);
require(success, "Could not transfer token. Missing approval?");
bulkMint(_msgSender(), amount);
}

UCommerce Prevent Users from adding new items during checkout

I have an Ecommerce website build with UCommerce. During the checkout process the user will be redirected to the payment portal for the payment.
I want to prevent users from adding new items in the basket while the user is in the payment portal. My current solution is to save the basket to a Session before redirecting the user to the payment portal.
Session["checkoutOrder"] = TransactionLibrary.GetBasket(!TransactionLibrary.HasBasket()).PurchaseOrder;
How can I overwrite the current basket with the one in the Session After the payment? This is to revert the basket to its original state before the payment.
I tried this:
[HttpPost]
public ActionResult ExecutePayment()
{
var order = Session["checkoutOrder"] as PurchaseOrder;
order.Save();
...
}
But I'm getting an error on order.Save():
Batch update returned unexpected row count from update; actual row count: 0; expected: 1
I'd just add to this as well that your Session["orderInProcess"] is an anti pattern in uCommerce. You may run into nasty exceptions as you're persisting NHibernate entities through requests which can/will lead to Session disposed exceptions. It may also lead to the initial exception that you're experiencing as you're actually by-passing the sesssion state of NHibernate.
Just use TransactionLibrary.GetBasket(!TransactionLibrary.HasBasket()).PurchaseOrder; every time you're retrieving your basket. NHibernate will take care of caching the order for you.
Then you can use order properties to save the state you're in.
var basket = TransactionLibrary.GetBasket(!TransactionLibrary.HasBasket()).PurchaseOrder;
basket["CheckoutInProcess"] = "True";
Best regards
Morten
I handled this differently since I have no way of reverting back the basket to its original state.
I decided to block the user from adding items in the basket when the payment is in process.
I created a session Session["orderInProcess"]=true before I redirect the user to the payment gateway.
Now every time the user tries to add a new item in the basket, I will check first if his current order is in process. like so:
[HttpPost]
public ActionResult AddToBasket(string sku, string quantity, string variant = null)
{
if (Session["orderInProcess"] != null)
{
if (bool.Parse(Session["orderInProcess"].ToString()))
{
return Json(new
{
Success = false,
ErrorMessage = "Order is currently in process."
});
}
}
.....
}
I hope this helps.

Update Data return Cannot insert duplicate key row in object

I'm working with Entity Framework and the structure for my DB is something like this:
An user have a collections of subscribers, so...
Subscriber:
Name
UserId
User (to navigate on user object)
if I get the subscriber without the user, I modify the "name" and commit the changes and all works fine, but if I get the subscriber with the user instanciated, in the CommitAndRefreshChanges, throws me:
Cannot insert duplicate key row in object 'dbo.User' with unique index 'PK_Email'.\r\nThe statement has been terminated
but I don't change anything for user... what I'm doing wrong?
To get the subscriber I run on the repository:
RegistrationModuleDataModelContainer context = UnitOfWork as RegistrationModuleDataModelContainer;
Subscriber subscriber = (from s in context.Subscribers.Include(it=>it.User)
where s.IdSubscriber == idSubscriber
select s).FirstOrDefault();
To modify the data use the next code:
Subscriber subscriber = this.GetSubscriberWithUser(idSubscriber);
subscriber.FirstName = FirstName;
subscriber.LastName = LastName;
//Condition with subscriber.User.x
subscriber.Email = Email;
_subscriberRepository.Modify(subscriber);
IUnitOfWork unitOfWork = _subscriberRepository.UnitOfWork;
unitOfWork.CommitAndRefreshChanges();
If I erase the condition, fails anyway, the problem is when I load the subscriber with the user, if I load the subscriber only, the commit works.
Thanks!

Entity framework and transaction in asp.net mvc application

I have question about managing transaction in asp.net application.
For example i have application for planning vacations.
Controller has form to approving vacations.
One user - click save and approve vacation ---- employee which want vacation has - 1 day
second user - clik save and approve vacation and ?
//pseudocode
public void ApproveVacation(int vacationId)
{
//pull vacationdata from db
var vacation = _dbContext.Vacations.FirstOrDefault(x => x.Id == vacationId);
if (vacation != null && vacation.State != approved) //
{
using (TransactionScope scope = new TransactionScope())
{
vacation.state = approved;
vacation.Employee.Days = -1;
_dbContext.saveChanges();
scope.complete();
}
}
}
And question is simple, is transaction enough for this scenario or I must use one of concurency technique?
Thanks
EDIT : Context is created one per request.
Transaction handles atomicity of the operation so if operation modifies multiple database records it will always result in consistent state where all records are correctly modified (if operation succeeds) or all changes are rolled back (if operation fails).
Concurrency handles possible modification of the same record by multiple processes / users because both could load original version of the record but one could save it first so when the second process tries to save a record it can silently override previous changes.
So what are you trying to handle in your code?
You already have an implicit transaction when calling 'SaveChanges' so there's no need for a transaction scope.
And also, if you would change several items you would need to start the TransactionScope before you retrieve the data.

SharePoint User Profile Search

Is there a way to search profiles in MOSS from the object model? I need to search for profiles that have a certain value set on their profile and then perform some action for them.
I need to write some c# code that can search the profiles database and return the matching profiles. Basically,
List of Profiles = Select Profiles From Profile Store Where Profile Property Value = SomeValue
I'm trying to avoid the following:
private IEnumerable<UserProfile> SearchProfiles(string value) {
ServerContext serverContext = ServerContext.GetContext(SPContext.Current.Site);
UserProfileManager profileManager = new UserProfileManager(serverContext);
foreach (UserProfile profile in profileManager) {
if ((string)profile["MyProp"].Value == value) {
yield return profile;
}
}
}
This is possible using the FullTextSqlQuery class:
FullTextSqlQuery q = new FullTextSqlQuery(ServerContext.Current);
q.ResultTypes = ResultType.RelevantResults;
q.QueryText = "SELECT UserName, Email, PreferredName FROM SCOPE() WHERE \"scope\" = 'People' AND Department = 'IT'";
ResultTableCollection tables = q.Execute();
ResultTable results = tables[ResultType.RelevantResults];
This class allows you to query a specific scope (i.e. people) and filter them based on properties using the WHERE clause, which looks basically the same as a regular Sql Query.
To be able to search and filter on (custom) user profile properties, the profile property needs to have a mapping in the Shared Service Provider's metadata settings. Most out of the box user profile properties already have these, custom properties you have to add yourself.
More info on managed properties here.
Two things:
when running with elevated privileges we need to create a new SPSite object within the call and load the security context from there. DO NOT use the context obtained using SPContext.Current.Site.
Hence:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite("<your site url>"))
{
ServerContext context = ServerContext.GetContext(site);
UserProfileManager profileManager = new
UserProfileManager(context);
foreach (UserProfile profile in profileManager)
{
// your code
}
}
}
make sure that the app pool account has appropriate user permissions in SSP. i.e. (use personal features, manage user profiles)

Resources