Warm tip: This article is reproduced from serverfault.com, please click

Retrieving a specific state in corda

发布于 2020-11-12 06:14:25

In My Corda project, I need to retrieve a specific state based on the some specific field of the state class, which I have set Unique for each state. How to do that in Corda? The implementation of state is as follows:

@BelongsToContract(OfferContract.class)
public class OfferState implements LinearState {
    private final UniqueIdentifier linearID;
    private AnonymousParty sender;
    private AnonymousParty receiver;
    private final String policyID;
    private final double faceValue;
    private double offeredAmount;

    private boolean isActive;

    public OfferState(UniqueIdentifier linearID, AnonymousParty sender, AnonymousParty receiver, String policyID, double faceValue, double offeredAmount, boolean isActive) {
        this.linearID = linearID;
        this.sender = sender;
        this.receiver = receiver;
        this.policyID = policyID;
        this.faceValue = faceValue;
        this.offeredAmount = offeredAmount;
        this.isActive = isActive;
    }

    public UniqueIdentifier getLinearID() {
        return linearID;
    }

    public AnonymousParty getSender() {
        return sender;
    }

    public AnonymousParty getReceiver() {
        return receiver;
    }

    public String getPolicyID() {
        return policyID;
    }

    public double getFaceValue() {
        return faceValue;
    }

    public double getOfferedAmount() {
        return offeredAmount;
    }

    public boolean isActive() {
        return isActive;
    }

    @NotNull
    @Override
    public UniqueIdentifier getLinearId() {
        return linearID;
    }

    @NotNull
    @Override
    public List<AbstractParty> getParticipants() {
        return Arrays.asList(sender,receiver);
    }

    @Override
    public String toString() {
        return super.toString();
    }
}

I am querying in the API with the following code But, that is showing empty brackets like [] in the postman output.

@GetMapping(value = "/getOfferWithID",headers = "Content-Type=application/x-www-form-urlencoded")
    private List<StateAndRef<OfferState>> getOfferWithID(HttpServletRequest request) throws IllegalArgumentException {
        String s  = request.getParameter("PolicyID");
        return proxy.vaultQuery(OfferState.class).getStates().stream().filter(it->it.getState().getData().getPolicyID().equalsIgnoreCase(s)).collect(Collectors.toList());
    }

Can you please tell me, How can I filter states while querying, What is going wrong here? is there any direct query method so that I can filter it in rpc call itself or Do I really need to wirte a flow for it?

Questioner
Vishwa Dayal
Viewed
1
Adel Rustum 2020-12-04 04:43:46

In order to be able to query your state by one of its attributes, you must:

  • Create a custom schema for your state, see here and here for examples.
  • Use VaultCustomQueryCriteria to query against your attribute policyId. Read about VaultCustomQueryCriteria here (search for that term, and look for sample code).

Your current approach (using .filter(it->it.getState().getData().getPolicyID().equalsIgnoreCase(s))) is very bad, essentially you are bringing a list of all of your states then filtering that list.
What are you going to do when your query returns 1000,000 states?! You are creating a list of 1000,000 entries then looping through that list to find that one record that has your policyId!!! This will simply drain your Java Heap, slow your application, and crash it.

Always delegate the search/query to the database by constructing the query in Corda then running it in the DB (using the approach that I already outlined), what you're currently doing is crafting a select * from some_table then looping through all of the results, my approach crafts select * from some_table where policyId = xxx, which will return one row.