【发布时间】:2018-06-20 14:31:07
【问题描述】:
我正在编写一个简单的 cordapp 来更新用户银行帐户的余额。以下是我更新某人帐户余额的步骤: 1. 使用创建流程创建线性状态 UserBalance。 2. 通过检索我使用 linearId 生成的未消费状态来更新状态的 balance 字段,并创建一个具有相同 linearId 但余额不同的新状态。 3.查询Vault中的UserBalance状态
问题: 当我在创建状态后第一次查询保险库时,我得到了:
{
"states" : [ {
"state" : {
"data" : {
"balance" : 0,
"accountOwner" : "O=PartyB, L=New York, C=US",
"linearId" : {
"externalId" : null,
"id" : "12800465-51bb-4700-9017-576bcecc6cec"
},
"participants" : [ "O=PartyB, L=New York, C=US", "O=PartyA, L=London, C=GB" ]
},
"contract" : "com.template.UserBalanceContract",
"notary" : "O=Notary, L=London, C=GB",
"encumbrance" : null,
"constraint" : { }
},
"ref" : {
"txhash" : "91B7429BE4E9B7E1579A12E764F601ED6912D432B6770E097F4EF027E145B17A",
"index" : 0
}
} ],
"statesMetadata" : [ {
"ref" : {
"txhash" : "91B7429BE4E9B7E1579A12E764F601ED6912D432B6770E097F4EF027E145B17A",
"index" : 0
},
"contractStateClassName" : "com.template.UserBalance",
"recordedTime" : 1529495492.423000000,
"consumedTime" : null,
"status" : "UNCONSUMED",
"notary" : "O=Notary, L=London, C=GB",
"lockId" : null,
"lockUpdateTime" : null
} ],
"totalStatesAvailable" : -1,
"stateTypes" : "UNCONSUMED",
"otherResults" : [ ]
}
但是在更新流程之后,由于余额已更新为新状态,因此运行成功,我得到了这个奇怪的查询结果:
{
"states" : [ {
"state" : {
"data" : {
"balance" : 0,
"accountOwner" : "O=PartyB, L=New York, C=US",
"linearId" : {
"externalId" : null,
"id" : "12800465-51bb-4700-9017-576bcecc6cec"
},
"participants" : [ "O=PartyB, L=New York, C=US", "O=PartyA, L=London, C=GB" ]
},
"contract" : "com.template.UserBalanceContract",
"notary" : "O=Notary, L=London, C=GB",
"encumbrance" : null,
"constraint" : { }
},
"ref" : {
"txhash" : "91B7429BE4E9B7E1579A12E764F601ED6912D432B6770E097F4EF027E145B17A",
"index" : 0
}
}, {
"state" : {
"data" : {
"balance" : 0,
"accountOwner" : "O=PartyB, L=New York, C=US",
"linearId" : {
"externalId" : null,
"id" : "12800465-51bb-4700-9017-576bcecc6cec"
},
"participants" : [ "O=PartyB, L=New York, C=US", "O=PartyA, L=London, C=GB" ]
},
"contract" : "com.template.UserBalanceContract",
"notary" : "O=Notary, L=London, C=GB",
"encumbrance" : null,
"constraint" : { }
},
"ref" : {
"txhash" : "988F38AE9F0EAC26F8B5095A3E1540304A8DF3047B10D3228ADE40B4BF928978",
"index" : 0
}
}, {
"state" : {
"data" : {
"balance" : 5,
"accountOwner" : "O=PartyB, L=New York, C=US",
"linearId" : {
"externalId" : null,
"id" : "12800465-51bb-4700-9017-576bcecc6cec"
},
"participants" : [ "O=PartyB, L=New York, C=US", "O=PartyA, L=London, C=GB" ]
},
"contract" : "com.template.UserBalanceContract",
"notary" : "O=Notary, L=London, C=GB",
"encumbrance" : null,
"constraint" : { }
},
"ref" : {
"txhash" : "988F38AE9F0EAC26F8B5095A3E1540304A8DF3047B10D3228ADE40B4BF928978",
"index" : 1
}
} ],
"statesMetadata" : [ {
"ref" : {
"txhash" : "91B7429BE4E9B7E1579A12E764F601ED6912D432B6770E097F4EF027E145B17A",
"index" : 0
},
"contractStateClassName" : "com.template.UserBalance",
"recordedTime" : 1529495492.423000000,
"consumedTime" : null,
"status" : "UNCONSUMED",
"notary" : "O=Notary, L=London, C=GB",
"lockId" : null,
"lockUpdateTime" : null
}, {
"ref" : {
"txhash" : "988F38AE9F0EAC26F8B5095A3E1540304A8DF3047B10D3228ADE40B4BF928978",
"index" : 0
},
"contractStateClassName" : "com.template.UserBalance",
"recordedTime" : 1529495581.759000000,
"consumedTime" : null,
"status" : "UNCONSUMED",
"notary" : "O=Notary, L=London, C=GB",
"lockId" : null,
"lockUpdateTime" : null
}, {
"ref" : {
"txhash" : "988F38AE9F0EAC26F8B5095A3E1540304A8DF3047B10D3228ADE40B4BF928978",
"index" : 1
},
"contractStateClassName" : "com.template.UserBalance",
"recordedTime" : 1529495581.759000000,
"consumedTime" : null,
"status" : "UNCONSUMED",
"notary" : "O=Notary, L=London, C=GB",
"lockId" : null,
"lockUpdateTime" : null
} ],
"totalStatesAvailable" : -1,
"stateTypes" : "UNCONSUMED",
"otherResults" : [ ]
}
因此,当我尝试使用相同的 linearId 更新新状态时,我发现 3 个未使用的状态具有相同的 linearId。并且操作失败了……
有人知道为什么会这样吗?以下是我的状态和流程代码:
package com.template;
import com.google.common.collect.ImmutableList;
import net.corda.core.contracts.LinearState;
import net.corda.core.contracts.UniqueIdentifier;
import net.corda.core.identity.AbstractParty;
import net.corda.core.identity.Party;
import java.util.List;
public class UserBalance implements LinearState {
private int balance;
private Party accountOwner;
private Party bank;
private final UniqueIdentifier linearId;
public UserBalance(int balance, Party accountOwner, Party bank, UniqueIdentifier linearId){
this.balance = balance;
this.accountOwner = accountOwner;
this.bank = bank;
this.linearId = linearId;
}
public int getBalance(){
return balance;
}
public Party getAccountOwner() {return accountOwner;}
@Override
public UniqueIdentifier getLinearId(){
return linearId;
}
@Override
public List<AbstractParty> getParticipants() {
return ImmutableList.of(accountOwner, bank);
}
}
package com.template;
import co.paralleluniverse.fibers.Suspendable;
import com.google.common.collect.ImmutableList;
import net.corda.core.contracts.Command;
import net.corda.core.contracts.StateAndContract;
import net.corda.core.contracts.UniqueIdentifier;
import net.corda.core.flows.*;
import net.corda.core.identity.Party;
import net.corda.core.transactions.SignedTransaction;
import net.corda.core.transactions.TransactionBuilder;
import net.corda.core.utilities.ProgressTracker;
import java.security.PublicKey;
import java.util.List;
@InitiatingFlow
@StartableByRPC
public class CreateUserBalanceFlow extends FlowLogic<Void> {
private final int balance;
private final Party accountOwner;
private final UniqueIdentifier linearId;
private final ProgressTracker progressTracker = new ProgressTracker();
// constructor
public CreateUserBalanceFlow(int initialBalance, Party accountOwner, String linearId){
this.balance = initialBalance;
this.accountOwner = accountOwner;
this.linearId = UniqueIdentifier.Companion.fromString(linearId);
}
@Override
public ProgressTracker getProgressTracker(){
return progressTracker;
}
/**
* The flow logic is encapsulated within the call() method.
*/
@Suspendable
@Override
public Void call() throws FlowException {
final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
final TransactionBuilder txBuilder = new TransactionBuilder();
txBuilder.setNotary(notary);
//create transactionComponent
//create output state
UserBalance outputState = new UserBalance(balance, accountOwner, getOurIdentity(), linearId);
StateAndContract outputStateAndContract = new StateAndContract(outputState, UserBalanceContract.UserBalance_Contract_ID);
List<PublicKey> requiredSigners = ImmutableList.of(getOurIdentity().getOwningKey());
//create the create command
Command cmd = new Command<>(new UserBalanceContract.Create(),requiredSigners);
txBuilder.withItems(outputStateAndContract, cmd);
txBuilder.verify(getServiceHub());
final SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder);
subFlow(new FinalityFlow(signedTx));
return null;
}
}
package com.template;
import co.paralleluniverse.fibers.Suspendable;
import com.google.common.collect.ImmutableList;
import net.corda.core.contracts.Command;
import net.corda.core.contracts.StateAndContract;
import net.corda.core.contracts.UniqueIdentifier;
import net.corda.core.flows.*;
import net.corda.core.identity.Party;
import net.corda.core.node.services.Vault;
import net.corda.core.node.services.vault.QueryCriteria;
import net.corda.core.contracts.StateAndRef;
import net.corda.core.transactions.SignedTransaction;
import net.corda.core.transactions.TransactionBuilder;
import net.corda.core.utilities.ProgressTracker;
import java.security.PublicKey;
import java.util.List;
@InitiatingFlow
@StartableByRPC
public class UpdateUserBalanceFlow extends FlowLogic<Void> {
private final UniqueIdentifier linearId;
private final int changeInBalance;
private final ProgressTracker progressTracker = new ProgressTracker();
//Constructor
public UpdateUserBalanceFlow(String linearId, int changeInBalance){
this.linearId = UniqueIdentifier.Companion.fromString(linearId);
this.changeInBalance = changeInBalance;
}
@Override
public ProgressTracker getProgressTracker(){
return progressTracker;
}
@Override
@Suspendable
public Void call() throws FlowException {
final Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
final TransactionBuilder txBuilder = new TransactionBuilder();
txBuilder.setNotary(notary);
//retrieve the input state
QueryCriteria queryCriteria = new QueryCriteria.LinearStateQueryCriteria(
null,
ImmutableList.of(linearId),
Vault.StateStatus.UNCONSUMED,
null);
List<StateAndRef<UserBalance>> UserBalances = getServiceHub().getVaultService().queryBy(UserBalance.class, queryCriteria).getStates();
if (UserBalances.size() != 1) {
throw new FlowException(String.format(UserBalances.size() + UserBalances.toString()));
}
UserBalance inputUserBalance = UserBalances.get(0).getState().getData();
//get the existing balance
int existingBalance = inputUserBalance.getBalance();
Party accountOwner = inputUserBalance.getAccountOwner();
int newBalance = existingBalance + changeInBalance;
//create output state
UserBalance outputUserBalance = new UserBalance(newBalance, accountOwner, getOurIdentity(), linearId);
//Build the transaction
List<PublicKey> requiredSigners = ImmutableList.of(getOurIdentity().getOwningKey());
StateAndContract outputStateAndContract = new StateAndContract(outputUserBalance, UserBalanceContract.UserBalance_Contract_ID);
StateAndContract inputStateAndContract = new StateAndContract(inputUserBalance, UserBalanceContract.UserBalance_Contract_ID);
Command cmd = new Command<>(new UserBalanceContract.Update(),requiredSigners);
txBuilder.withItems(inputStateAndContract, outputStateAndContract, cmd);
txBuilder.verify(getServiceHub());
final SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder);
subFlow(new FinalityFlow(signedTx));
return null;
}
}
谢谢!
【问题讨论】:
标签: corda