【问题标题】:CORDA Error validating transaction between two partysCORSA 验证两方之间的交易时出错
【发布时间】:2020-06-24 23:38:27
【问题描述】:

我收到以下错误:

[ERROR] 14:37:15-0400 [Node thread-1] internal.Verifier。 - 验证交易 95C242529D07CCC5F657909F7A1D40EF8F5BD5D748D81E97C3E4F2534BC54334 时出错。 [errorCode=1oup47m, moreInformationAt=https://errors.corda.net/OS/4.4/1oup47m] {actor_id=internalShell, actor_owning_identity=O=Toyota, L=London, C=GB, actor_store_id=NODE_CONFIG, fiber-id= 10000001, flow-id=b716ec51-d40e-4a9e-a7bc-d3e917ea6dd8, invocation_id=a317a00a-af20-454a-bcc7-02d131be67c7, invocation_timestamp=2020-06-23T18:37:13.897Z, origin_7b96, origin_7b96, -4771-8b40-36a30312fa91, session_timestamp=2020-06-23T18:37:12.984Z, thread-id=188}

当我尝试从 Corda 节点(丰田)终端运行时:

start CarRegistrationFlowInitiator carMake: Toyota , carModel: Rav4 , carYear: 2016 , carMileage: 31424.0 , carVin: asdfghjkloiu76543 , carOwner: "O=AutoSmart,L=New York,C=US"

我有两个派对 Toyota 和 AutoSmart。丰田是发行人,AutoSmart 是所有者。

汽车状态:


import com.template.contracts.CarContract;
import net.corda.core.contracts.BelongsToContract;
import net.corda.core.contracts.ContractState;
import net.corda.core.identity.AbstractParty;
import net.corda.core.identity.Party;
import org.jetbrains.annotations.NotNull;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@BelongsToContract(CarContract.class)
public class CarState implements ContractState {

    private String carMake;
    private String carModel;
    private int carYear;
    private float carMileAge;
    private String carVIN;
    private Party issuer;
    private Party owner;

    public CarState(String carMake, String carModel, int carYear, float carMileAge, String carVIN, Party issuer, Party owner) {
        this.carMake = carMake;
        this.carModel = carModel;
        this.carYear = carYear;
        this.carMileAge = carMileAge;
        this.carVIN = carVIN;
        this.issuer = issuer;
        this.owner = owner;
    }


    public String getCarMake() {
        return carMake;
    }

    public String getCarModel() {
        return carModel;
    }

    public int getCarYear() {
        return carYear;
    }

    public float getCarMileAge() {
        return carMileAge;
    }

    public String getCarVIN() {
        return carVIN;
    }

    public Party getIssuer(){
        return issuer;
    }

    public Party getOwner(){
        return owner;
    }

    @NotNull
    @Override
    public List<AbstractParty> getParticipants() {
        return Arrays.asList(issuer,owner);

    }
}

汽车合同


import net.corda.core.contracts.Command;
import net.corda.core.contracts.CommandData;
import net.corda.core.contracts.Contract;
import net.corda.core.contracts.ContractState;
import net.corda.core.identity.Party;
import net.corda.core.transactions.LedgerTransaction;
import org.jetbrains.annotations.NotNull;
import com.template.states.CarState;

import java.awt.*;
import java.security.PublicKey;
import java.util.List;

public class CarContract implements Contract {
    public static final String CID = "com.template.contracts.CarContract";

    @Override
    public void verify(@NotNull LedgerTransaction tx) throws IllegalArgumentException {


    // shape constraints
    if (tx.getCommands().size()!=1){
        throw new IllegalArgumentException("Should contain only one command");
    }

    Command command = tx.getCommand(0);
    CommandData commandType = command.getValue();

    if(commandType instanceof Register){

        // shape constraints
        if (!(tx.getInputStates().size()!=0)){
            throw new IllegalArgumentException("Registration contract should have no input states.");
        }

        if (tx.getOutputStates().size() != 1){
            throw new IllegalArgumentException("Registration contract should only have single output state");
        }

        // content constraints
        ContractState outputState = tx.getOutput(0);

        if (!(outputState instanceof CarState)){
            throw new IllegalArgumentException("Not a car state");
        }


        if (!((CarState) outputState).getCarMake().equals("Toyota") ||
                ((CarState) outputState).getCarMake().equals("Honda") ||
                ((CarState) outputState).getCarMake().equals("Subaru")){
            throw new IllegalArgumentException("Car must be either a Honda, Toyota or a Subaru");
        }

        if (((CarState) outputState).getCarYear()<2015){
            throw new IllegalArgumentException("Car must not be older than 2015 year model.");
        }

        if (((CarState) outputState).getCarVIN().length()!=17){
            throw new IllegalArgumentException("VIN must be 17 characters in length and valid.");
        }
        //signers constraints
        Party issuer = ((CarState) outputState).getIssuer();
        PublicKey issuerKey = issuer.getOwningKey();

        List<PublicKey> requiredSigners = command.getSigners();
        if (!(requiredSigners.contains(issuerKey))){
            throw new IllegalArgumentException("Both issuer and owner of car must sign the contract.");
        }

    }
    else{

        throw new IllegalArgumentException("Commnd type not recognixed");
    }

     //
    }

    public static class Register implements CommandData{};

}

CarRegistrationFlowInitiator


import co.paralleluniverse.fibers.Suspendable;


import com.template.contracts.CarContract;
import com.template.states.CarState;
import net.corda.core.contracts.Command;
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.ArrayList;



@InitiatingFlow
@StartableByRPC
public class CarRegistrationFlowInitiator extends FlowLogic<String> {

    private String carMake;
    private String carModel;
    private int carYear;
    private String carVin;
    private float carMileage;
    private Party carOwner;

    public CarRegistrationFlowInitiator(String carMake, String carModel, int carYear, float carMileage, String carVin, Party carOwner) {
        this.carMake = carMake;
        this.carModel = carModel;
        this.carYear = carYear;
        this.carMileage = carMileage;
        this.carVin = carVin;
        this.carOwner = carOwner;

    }

    private final ProgressTracker.Step RETRIEVING_NOTARY = new ProgressTracker.Step("Retrieving Notary");
    private final ProgressTracker.Step CREATE_TRANSACTION_OUTPUT= new ProgressTracker.Step("Creating Transaction Output");
    private final ProgressTracker.Step  CREATE_TRANSACTION_BUILDER= new ProgressTracker.Step("Creating transaction Builder");
    private final ProgressTracker.Step SIGN_TRANSACTION = new ProgressTracker.Step("Signing Transaction");
    private final ProgressTracker.Step INITIATE_SESSION = new ProgressTracker.Step("Initiating session with counterparty");
    private final ProgressTracker.Step FINALIZE_FLOW = new ProgressTracker.Step("Finalizing the flow");


    private final ProgressTracker progressTracker = new ProgressTracker(
            RETRIEVING_NOTARY,
            CREATE_TRANSACTION_OUTPUT,
            CREATE_TRANSACTION_BUILDER,
            SIGN_TRANSACTION,
            INITIATE_SESSION,
            FINALIZE_FLOW
    );
    private Party counterParty;

    @Override
    public ProgressTracker getProgressTracker() {
        return progressTracker;
    }



    @Suspendable
    public String call() throws FlowException {

    //Retrieve the notary identity from the network map
        progressTracker.setCurrentStep(RETRIEVING_NOTARY);
        Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);


    //Create  transaction components inputs and outputs
        progressTracker.setCurrentStep(CREATE_TRANSACTION_OUTPUT);
        CarState outputState = new CarState(carMake,carModel,carYear,carMileage,carVin,getOurIdentity(),carOwner);

   // Create the transaction builder here and add compenents to it
        progressTracker.setCurrentStep(CREATE_TRANSACTION_BUILDER);
        TransactionBuilder txB = new TransactionBuilder(notary);
     //   PublicKey issuerKey = getServiceHub().getMyInfo().getLegalIdentitiesAndCerts().get(0).getOwningKey();
       // PublicKey ownerKey = carOwner.getOwningKey();
        //List<PublicKey> requiredSigners = ImmutableList.of(issuerKey,ownerKey);
        //ArrayList<PublicKey> requiredSigners = new ArrayList<PublicKey>();
        //requiredSigners.add(issuerKey);
        //requiredSigners.add(ownerKey);


        Command cmd = new Command(new CarContract.Register(), getOurIdentity().getOwningKey());
        txB.addOutputState(outputState,"com.template.contracts.CarContract")
                .addCommand(cmd);

    // Sign the transaction
        progressTracker.setCurrentStep(SIGN_TRANSACTION);
        SignedTransaction signedTx = getServiceHub().signInitialTransaction(txB);


     // Create session with counterparty
        progressTracker.setCurrentStep(INITIATE_SESSION);
        FlowSession otherPartySession = initiateFlow(carOwner);
    //Finalizing  the transaction
        progressTracker.setCurrentStep(FINALIZE_FLOW);
        subFlow(new FinalityFlow(signedTx,otherPartySession));

    return "Registration Completed";
    }
}

CarRegistrationFlowResponder


import co.paralleluniverse.fibers.Suspendable;
import net.corda.core.flows.*;

@InitiatedBy(CarRegistrationFlowInitiator.class)
public class CarRegistrationFlowResponder extends FlowLogic<String> {
    private FlowSession otherPartySession;

    public CarRegistrationFlowResponder(FlowSession otherPartySession) {
        this.otherPartySession = otherPartySession;
    }

    @Suspendable
    @Override
    public String call() throws FlowException {
        // Responder flow logic goes here.
        subFlow(new ReceiveFinalityFlow(otherPartySession));
        return "Registration received!";
    }
}

【问题讨论】:

  • 1- 请分享堆栈跟踪的更多输出以详细了解错误。 2-您的合同Both issuer and owner of car must sign the contract. 中的错误消息与您检查的内容不匹配(您只检查issuer 签名:if (!(requiredSigners.contains(issuerKey))))。 3-您应该在签署之前验证交易(即在signInitialTransaction(txB)之前添加txB.verify(),签署可能无效的交易有什么意义?一旦您分享有关错误的更多详细信息并进行修复,我可能可以识别发生了什么事。
  • 另外,为什么你不使用requireThat / require 语法而不是if 语句?参见示例here
  • 并使用requireSingleCommand 来验证它是单个命令。

标签: java corda


【解决方案1】:

我发现合同中这部分代码存在问题。

    // shape constraints
    if (!(tx.getInputStates().size()!=0)){
        throw new IllegalArgumentException("Registration contract should have no input states.");
    }

输入大小应为零。但是你否定了这个条件。这意味着如果输入大小实际上为零,则会出现异常。

而且您在交易中没有输入,所以这应该会引发合约验证异常

【讨论】:

    猜你喜欢
    • 2019-02-22
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-26
    相关资源
    最近更新 更多