Corda transactions happens between 2 node? is there a way we can do a transaction between more then 2 nodes? [duplicate] - corda

I've been trying to learn Corda and I have a specific use case for a contract which involved multiple participants.
Forgive me if my understanding is incorrect and please correct me if I'm wrong! :)
From what I understand, the contract is where we implement the verification functionality for a a transaction that calls upon said contract.
The state can hold the 'state' of a current transaction along with any data regarding the transaction.
The flow is the the business logic associated with a state/contract.
I have a specific use case that I want to address within a contract, and this involves multiple parties that share the same contract/transaction info.
I want a state to be able to hold multiple participants.
Purely from what I understand, I have coded the following for a state:
#BelongsToContract(MasterContract.class)
public class MasterState implements ContractState {
private final List<Party> employers = emptyList();
private final List<Party> contractors = emptyList();
private final String projectName;
public MasterState(String projectName, List<Party> employers, List<Party> contractors) {
this.projectName = projectName;
this.employers.addAll(employers);
this.contractors.addAll(contractors);
}
public String getProjectName() {
return projectName;
}
public List<Party> getEmployers() {
return employers;
}
public List<Party> getContractors() {
return contractors;
}
#Override
public List<AbstractParty> getParticipants() {
List<AbstractParty> allParts = new ArrayList<>();
allParts.addAll(employers);
allParts.addAll(contractors);
return allParts;
}
}
I want to be able to create (via a Command) a new instance of MasterContract by providing multiple 'employers' or 'contractors'.
I am trying to define: MasterCreationFlow.call() as follows:
#Suspendable
#Override
public Void call() throws FlowException {
Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
// Create the transaction components
JCTMasterState outputState = new JCTMasterState(projectName, Arrays.asList(getOurIdentity()), contractors);
//List of required signers:
List<PublicKey> requiredSigners = Arrays.asList(getOurIdentity().getOwningKey());
requiredSigners.addAll(getOwningKeys(contractors));
Command createCommand = new Command<>(new JCTMasterContract.Create(), requiredSigners);
...
However, I'm stuck with the idea of InitiateFlow(). As it seems like you can only do this between 2 parties. I understand that Corda is point-to-point. But I want to understand what exactly FlowSession does? So far, I have read that FlowSessions are just a channel between 2 parties that is then consumed by some SubFlow. Is there any way to extend FlowSession to create a shared session between multiple counter-parties? Or would I have to initiate multiple flows?
Thanks in advance!

You are right that FlowSession is between 2 parties, which is the party calling initiateFlow(someParty) method and someParty.
So, in order for you to create multiple sessions between your flow initiator and your contractors, you can do this:
Set<FlowSession> sessions = contractors.stream().map(it ->
initiateFlow(it)).collect(Collectors.toSet());
Then for instance you can pass the sessions to collect signatures from the contractors:
final SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow(partSignedTx,
sessions, CollectSignaturesFlow.Companion.tracker()));

On top of the proposed solution by Adel ( https://stackoverflow.com/a/60438425/7733418 ) adding the Owners Public key into the signer list might be necessary, if not yet done.

Related

Using Akka.net with Asp.net on a Modular Monolith architecture

Iwould like to implement a rest service using Akka and Asp.net.
Following the example here
I create my AkkaService containing the FooActor ref and a controller who transform the http request to a RunProcess message which is sent to the FooActor.
[Route("api/[controller]")]
[ApiController]
public class MyController : Controller
{
private readonly ILogger<MyController> _logger;
private readonly IAkkaService Service;
public RebalancingController(ILogger<MyController> logger, IAkkaService bridge)
{
_logger = logger;
Service = bridge;
}
[HttpGet]
public async Task<ProcessTerminated> Get()
{
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));
return await Service.RunProcess(cts.Token);
}
}
public class AkkaService : IAkkaService, IHostedService
{
private ActorSystem ActorSystem { get; set; }
public IActorRef FooActor { get; private set; }
private readonly IServiceProvider ServiceProvider;
public AkkaService(IServiceProvider sp)
{
ServiceProvider = sp;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
var hocon = ConfigurationFactory.ParseString(await File.ReadAllTextAsync("app.conf", cancellationToken));
var bootstrap = BootstrapSetup.Create().WithConfig(hocon);
var di = DependencyResolverSetup.Create(ServiceProvider);
var actorSystemSetup = bootstrap.And(di);
ActorSystem = ActorSystem.Create("AkkaSandbox", actorSystemSetup);
// </AkkaServiceSetup>
// <ServiceProviderFor>
// props created via IServiceProvider dependency injection
var fooProps = DependencyResolver.For(ActorSystem).Props<FooActor>();
FooActor = ActorSystem.ActorOf(rebalProps.WithRouter(FromConfig.Instance), "foo");
// </ServiceProviderFor>
await Task.CompletedTask;
}
public async Task<ProcessTerminated> RunProcess(CancellationToken token)
{
return await FooActor.Ask<ProcessTerminated>(new RunProcess(), token);
}
public FooActor(IServiceProvider sp)
{
_scope = sp.CreateScope();
Receive<RunProcess>(x =>
{
var basketActor = Context.ActorOf(Props.Create<BarActor>(sp), "BarActor");
basketActor.Tell(new BarRequest());
_log.Info($"Sending a request to Bar Actor ");
});
Receive<BarResponse>(x =>
{
...... Here I need to send back a ProcessTerminated message to the controller
});
}
Now, let's imagine the FooActor send a message to the BarActor telling him to perform a given task and wait the BarResponse. How could I send back the ProcessTerminated message to the controller?
Few points to take into considerations:
I want to ensure no coupling between BarActor and FooActor.
By example, I could add the original sender ActorRef to the BarRequest and
BarResponse. But the BarActor musn't know about the fooActor and
MyController. The structure of the messages an how the barActor
respond should not be dependent of what the FooActor do with the
BarResponse.
In the example I only use BarActor, but we can imagine to have many different actors
exchanging messages before returning the final result to the controller.
Nitpick: you should use Akka.Hosting and avoid creating this mock wrapper service around the ActorSystem. That will allow you to pass in the ActorRegistry directly into your controller, which you can use to then access FooActor without the need for additional boilerplate. See "Introduction to Akka.Hosting - HOCONless, "Pit of Success" Akka.NET Runtime and Configuration" video for a fuller explanation.
Next: to send the ProcessTerminated message back to your controller you need to save the Sender (the IActorRef that points to the temporary actor created by Ask<T>, in this instance) during your Receive<RunProcess> and make sure that this value is available inside your Receive<BarResponse>.
The simple ways to accomplish that:
Store the Sender in a field on the FooActor, use behavior-switching while you wait for the BarActor to respond, and then revert back to your original behavior.
Build a Dictionary<RunProcess, IActorRef> (the key should probably actually be some unique ID shared by RunProcess and BarResponse - a "correlation id") and reply to the corresponding IActorRef stored in the dictionary when BarResponse is received. Remove the entry after processing.
Propagate the Sender in the BarRequest and BarResponse message payloads themselves.
All three of those would work. If I thought there were going to be a large number of RunProcess requests running in parallel I'd opt for option 2.
Another way of doing it is by simply forwarding the next message to the next actor. The Tell operation have a second parameter that can be used to override the message sender. If you're sure that all path has to respond back to the original Ask inside the Http controller, you can do this inside the FooActor:
Receive<RunProcess>(x =>
{
var basketActor = Context.ActorOf(Props.Create<BarActor>(sp), "BarActor");
basketActor.Tell(new BarRequest(), Sender);
_log.Info($"Sending a request to Bar Actor ");
});
This way, the original Ask actor is considered as the sender of the new BarRequest message instead of the FooActor, and if BarActor decide to reply by doing a Sender.Tell(new ProcessTerminated()). the ProcessTerminated message will be sent to the Http controller.

Can you create flow sessions for multiple participants in Corda

I've been trying to learn Corda and I have a specific use case for a contract which involved multiple participants.
Forgive me if my understanding is incorrect and please correct me if I'm wrong! :)
From what I understand, the contract is where we implement the verification functionality for a a transaction that calls upon said contract.
The state can hold the 'state' of a current transaction along with any data regarding the transaction.
The flow is the the business logic associated with a state/contract.
I have a specific use case that I want to address within a contract, and this involves multiple parties that share the same contract/transaction info.
I want a state to be able to hold multiple participants.
Purely from what I understand, I have coded the following for a state:
#BelongsToContract(MasterContract.class)
public class MasterState implements ContractState {
private final List<Party> employers = emptyList();
private final List<Party> contractors = emptyList();
private final String projectName;
public MasterState(String projectName, List<Party> employers, List<Party> contractors) {
this.projectName = projectName;
this.employers.addAll(employers);
this.contractors.addAll(contractors);
}
public String getProjectName() {
return projectName;
}
public List<Party> getEmployers() {
return employers;
}
public List<Party> getContractors() {
return contractors;
}
#Override
public List<AbstractParty> getParticipants() {
List<AbstractParty> allParts = new ArrayList<>();
allParts.addAll(employers);
allParts.addAll(contractors);
return allParts;
}
}
I want to be able to create (via a Command) a new instance of MasterContract by providing multiple 'employers' or 'contractors'.
I am trying to define: MasterCreationFlow.call() as follows:
#Suspendable
#Override
public Void call() throws FlowException {
Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
// Create the transaction components
JCTMasterState outputState = new JCTMasterState(projectName, Arrays.asList(getOurIdentity()), contractors);
//List of required signers:
List<PublicKey> requiredSigners = Arrays.asList(getOurIdentity().getOwningKey());
requiredSigners.addAll(getOwningKeys(contractors));
Command createCommand = new Command<>(new JCTMasterContract.Create(), requiredSigners);
...
However, I'm stuck with the idea of InitiateFlow(). As it seems like you can only do this between 2 parties. I understand that Corda is point-to-point. But I want to understand what exactly FlowSession does? So far, I have read that FlowSessions are just a channel between 2 parties that is then consumed by some SubFlow. Is there any way to extend FlowSession to create a shared session between multiple counter-parties? Or would I have to initiate multiple flows?
Thanks in advance!
You are right that FlowSession is between 2 parties, which is the party calling initiateFlow(someParty) method and someParty.
So, in order for you to create multiple sessions between your flow initiator and your contractors, you can do this:
Set<FlowSession> sessions = contractors.stream().map(it ->
initiateFlow(it)).collect(Collectors.toSet());
Then for instance you can pass the sessions to collect signatures from the contractors:
final SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow(partSignedTx,
sessions, CollectSignaturesFlow.Companion.tracker()));
On top of the proposed solution by Adel ( https://stackoverflow.com/a/60438425/7733418 ) adding the Owners Public key into the signer list might be necessary, if not yet done.

Corda Tokens SDK: "There is a token group with no assigned command" error

I already solved this problem, but I would like to understand why it occurred in the first place:
1. I'm using the Java template of Tokens SDK
2. I created my own token type
3. I modified ExampleFlowWithFixedToken class to issue my new token
4. When I ran start ExampleFlowWithFixedToken amount: 100, recipient: PartyB, I got the error: There is a token group with no assigned command
5. Initially my new token class didn't implement the equals() method, when I added it; the error was gone and I was able to issue my token.
Why adding that method, fixes the problem?
public class MyTokenType implements TokenType {
private final int fractionDigits = 6;
private final String tokenIdentifier = "MY_TOKEN";
#NotNull
#Override
public BigDecimal getDisplayTokenSize() {
return BigDecimal.ONE.scaleByPowerOfTen(-fractionDigits);
}
#Override
public int getFractionDigits() {
return fractionDigits;
}
#NotNull
#Override
public Class<?> getTokenClass() {
return this.getClass();
}
#NotNull
#Override
public String getTokenIdentifier() {
return tokenIdentifier;
}
#Override
public boolean equals(Object obj) {
return obj instanceof MyTokenType;
}
}
ExampleFlowWithFixedToken calls the built-in IssueTokens Flow.
This flow , builds the transaction internally specifying input, output states, commands(IssueCommand in this case).
Next step is to verify the contract.
Before verifying the contracts we group the input/output tokens by the issuer.
Each group is then assigned a token command.
This is done because if a transaction contains more than one type of token, they need to grouped by IssuedTokenType.
Also note same token type issued by different issuers are not fungible.
Hence the grouping by IssuedTokenType is required.
Once we have the groups by IssuedTokenType, contract verification is done separately for each group.
When we try to assign a token command to each group , we compare the IssuedTokenType in command to one in our groups.
So if we dont override equals method, none of the IssuedTokenType from the groups will match to the one in the TokenCommand.
Hence the group will not be assigned any TokenCommand.
Each group should at least have one command. If there isn’t then we would not know what to do with that group. Hence it fails saying "There is a token group with no assigned command"
Hope that helps!

Multi-entity Aggregates command handling

I have an aggregate root like this:
Aggregate root:
#NoArgsConstructor
#Aggregate(repository = "positionAggregateRepository")
#AggregateRoot
#XSlf4j
#Data
public class HopAggregate {
#AggregateIdentifier
private String hopId;
private FilteredPosition position;
private LocalDate positionDate;
#AggregateMember
private Security security;
#CommandHandler
public HopAggregate(NewHopCommand cmd) {
log.info("creating new position , {}", cmd.getDateId());
apply(new HopEvent(cmd.getHopId(), cmd.getDateId(), cmd.getFilteredPosition(), cmd.getSecurity(), false));
}
#CommandHandler
public void handle(UpdateHopCommand cmd) {
log.info("creating hop update event {}", cmd);
apply(new HopEvent(this.hopId, this.positionDate, cmd.getFilteredPosition(), this.security, true));
}
#CommandHandler
public void handle(SecurityUpdate cmd) {
log.info("updating security {}", cmd);
apply(new SecurityUpdateEvent(this.hopId, cmd.getFilteredSecurity()));
}
#EventSourcingHandler
public void on(HopEvent evt) {
if (evt.getIsUpdate()) {
log.info("updating position {}", evt);
this.position = evt.getFilteredPosition();
} else {
log.info("adding new position to date {}", evt);
this.hopId = evt.getHopId();
this.positionDate = evt.getDate();
this.position = evt.getFilteredPosition();
this.security= evt.getSecurity();
}
}
#EventSourcingHandler
public void on(SecurityUpdateEvent evt) {
log.info("hop id {}, security update {}", this.hopId, evt.getFilteredSecurity().getSecurityId());
}
}
Child entity:
#XSlf4j
#Data
#RequiredArgsConstructor
#NoArgsConstructor
public class IpaSecurity implements Serializable {
#EntityId
#NonNull
private String id;
#NonNull
private FilteredSecurity security;
}
My issue is that when i am pushing and update like this:
#EventHandler
public void handleSecurityEvent(SecurityUpdate securityUpdate) {
log.info("got security event {}", securityUpdate);
commandGateway.send(securityUpdate);
}
and my command being:
#Data
#RequiredArgsConstructor
#NoArgsConstructor
#ToString
public class SecurityUpdate {
#NonNull
#TargetAggregateIdentifier
private String id;
#NonNull
private FilteredSecurity filteredSecurity;
}
I am getting aggregate root not found exception:
Command 'com.hb.apps.ipa.events.SecurityUpdate' resulted in org.axonframework.modelling.command.AggregateNotFoundException(The aggregate was not found in the event store)
I am not sure how to handle this scenario. My requirement is that each aggregate should check whether it contains the security and then update it if the command was issued. What am i missing? let me know if you need any more info on the code.
Thanks for your help.
A Command is always targeted towards a single entity.
This entity can be an Aggregate, an entity contained in an Aggregate (what Axon Framework calls an Aggregate Member) or a simple singleton component.
Important to note though, is that there will only be one entity handling the command.
This is what requires you to set the #TargetAggregateIdentifier in your Command for Axon to be able to route it to a single Aggregate instance if the Command Handler in question is part of it.
The AggregateNotFoundException you're getting signals that the #TargetAggregateIdentifier annotated field in your SecurityUpdate command does no correspond to any existing Aggregate.
I'd thus suspect that the id field in the SecurityUpdate does not correspond to any #AggregateIdentifier annotated field in your HopAggregate aggregates.
A part from the above, I have a couple of other suggestions when looking at your snippets which I'd like to share with you:
#Aggregate is meta-annotated with #AggregateRoot. You're thus not required to specify both on an Aggregate class
For logging messages being handled, you can utilize LoggingInterceptor. You can configure this on any component capable of handling messages, thus providing a universal way of logging. This will omit the necessity to add log lines in your message handling functions
You're publishing a HopEvent on both the create and update commands. Doing so makes your HopEvent very generic. Ideally, your events clarify business operations occurring in your system. My rule of thumb typically is such: "If I tell my business manager/customer about the event class, he/she should know exactly what it does". I'd thus suggest to rename the event to something more specific
Just as with the HopEvent, the UpdateHopCommand is quite generic. Your commands should express the intent to perform an operation in your application. Users will typically not desire an update, they desire an address change for example. Your commands classes ideally reflect this
The suggested naming convention for commands is to start with verb in the present tense. Thus, it should no be SecurityUpdate, but UpdateSecurity. A command is a request expressing intent, the messages ideally reflect this
Hope this helps you out #juggernaut!

SignalR - Leave All Groups

Using a SignalR hub clients can be added or removed from a group. A client can belong to multiple groups. Is it possible to remove a client from every group it currently belongs to? I guess what I'm looking for is something like Clients[*allgroups*].leave(Context.ConnectionId)
As of v0.5.2, there is no way to leave all groups because the server doesn't keep track of the groups a client belongs to. You need to do this yourself and remove the client from each group one-by-one.
There's a request for something similar in the backlog however, so maybe this will be implemented in a future release: https://github.com/SignalR/SignalR/issues/66
Looks like they have yet to implement this, but it is considered a candidate for v3. A feature request with the following code exists at https://github.com/SignalR/SignalR/issues/66
public static class SignalRConnectionToGroupsMap
{
private static readonly ConcurrentDictionary<string, List<string>> Map = new ConcurrentDictionary<string, List<string>>();
public static bool TryAddGroup(string connectionId, string groupName)
{
List<string> groups;
if (!Map.TryGetValue(connectionId, out groups))
{
return Map.TryAdd(connectionId, new List<string>() {groupName});
}
if (!groups.Contains(groupName))
{
groups.Add(groupName);
}
return true;
}
// since for this use case we will only want to get the List of group names
// when we're removing the mapping - we might as well remove the mapping while
// we're grabbing the List
public static bool TryRemoveConnection(string connectionId, out List<string> result)
{
return Map.TryRemove(connectionId, out result);
}
}

Resources