【问题标题】:Corda LinearState: trying to transfer consumed state from one owner to the otherCorda LinearState:尝试将消费状态从一个所有者转移到另一个所有者
【发布时间】:2020-07-02 12:23:45
【问题描述】:

我正在尝试将状态从一个所有者转移到另一个所有者。所以总是以相同的值创建新的状态。但打算将状态传递给另一个所有者。试图用线性状态来实现这一点。我已经粘贴了基本上应该使用相同的汽车状态的转移流程,该状态是为跨车主转移而发出的。相同的消费汽车状态应该可以来回传输,相同的状态被一次又一次地消费。这在 Corda 中是否可行。从理论上讲,我试图在两方或多方之间来回转移汽车。

  @ConstructorForDeserialization
    public CarState(String carMake, String carModel, int carYear, double carMileAge, String carVIN, Party issuer, Party owner,UniqueIdentifier linearId) {
        this.carMake = carMake;
        this.carModel = carModel;
        this.carYear = carYear;
        this.carMileAge = carMileAge;
        this.carVIN = carVIN;
        this.issuer = issuer;
        this.owner = owner;
        this.linearId = linearId;
    }

合同


        if(!(inputState.getLinearId().getExternalId().equals(outputState.getLinearId().getExternalId()))){
            throw new IllegalArgumentException("UUID of input state and output state must be same");
        }

流程

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

//    private final String carMake;
//    private final String carModel;
//    private final int carYear;
    private final String carVin;
//    private final double carMileage;
    private final Party carOwner;
    private final UniqueIdentifier linearId;
    private int input;



    public CarTransferFlowInitiator(String carVin,Party carOwner,UniqueIdentifier linearId){
        this.carVin = carVin;
        this.carOwner = carOwner;
        this.linearId = linearId;
    }

    private final ProgressTracker.Step RETRIEVING_NOTARY = new ProgressTracker.Step("Retrieving Notary");
    private final ProgressTracker.Step CREATE_TRANSACTION_INPUT= new ProgressTracker.Step("Creating Transaction Input");
    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
    );


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


    public StateAndRef<CarState> checkForCarStates() throws FlowException {


        //QueryCriteria generalCriteria = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.UNCONSUMED);

        QueryCriteria generalCriteria = new QueryCriteria.VaultQueryCriteria(Vault.StateStatus.ALL);

        List<StateAndRef<CarState>> CarStates = getServiceHub().getVaultService().queryBy(CarState.class, generalCriteria).getStates();

        boolean inputFound = false;
        int t = CarStates.size();
        input = 0;
        for (int x = 0; x < t; x++) {
           if (CarStates.get(x).getState().getData().getCarVIN().equals(carVin)) {
           // if (CarStates.get(x).getState().getData().getLinearId().getExternalId().equals(linearId.getExternalId())) {
                input = x;
                inputFound = true;
            }
        }


        if (inputFound) {
            System.out.println("\n Input Found");
//            System.out.println(CarStates.get(input).getState().getData().getCarMake());
//            System.out.println(CarStates.get(input).getState().getData().getCarModel());
//            System.out.println(CarStates.get(input).getState().getData().getCarYear());
//            System.out.println(CarStates.get(input).getState().getData().getCarMileAge());
//            System.out.println(CarStates.get(input).getState().getData().getCarVIN());

        } else {
            System.out.println("\n Input not found");
            throw new FlowException();
        }

        return CarStates.get(input);
    }


    @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 both input and output for this application
        progressTracker.setCurrentStep(CREATE_TRANSACTION_OUTPUT);
        StateAndRef<CarState> inputState = null;
        inputState = checkForCarStates();


        //Issuer is Toyota
        //Owner is  AutoSmart

        Party issuer = inputState.getState().getData().getIssuer();
        PublicKey issuerKey = issuer.getOwningKey();

        //Create  transaction components both input and output for this application
        progressTracker.setCurrentStep(CREATE_TRANSACTION_OUTPUT);
        //CarState outputState = new CarState(carMake,carModel,carYear,carMileage,carVin,issuer,carOwner);

        String carMake = inputState.getState().getData().getCarMake();
        String carModel = inputState.getState().getData().getCarModel();
        int carYear = inputState.getState().getData().getCarYear();
        double carMile  = inputState.getState().getData().getCarMileAge();
        String carVIN = inputState.getState().getData().getCarVIN();
        Party carIssuer = inputState.getState().getData().getIssuer();
        UniqueIdentifier carLinearId = inputState.getState().getData().getLinearId();

        System.out.println(carLinearId);
        CarState outputState = new CarState(carMake,carModel,carYear,carMile, carVin,carIssuer,carOwner,carLinearId);

        List<PublicKey> requiresSigners = Arrays.asList(issuerKey,getOurIdentity().getOwningKey(),outputState.getOwner().getOwningKey());
//        requiresSigners.add(outputState.getIssuer().getOwningKey());
//        requiresSigners.add(outputState.getOwner().getOwningKey());

        final Command<CarContract.Transfer> txCommand = new Command<>(
                new CarContract.Transfer(),
                requiresSigners
        );

        final TransactionBuilder txBuilder = new TransactionBuilder(notary)
                .addInputState(inputState)
                .addOutputState(outputState, CID)
                .addCommand(txCommand);

        // 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, CID)
        //      .addCommand(cmd);

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






        // Create session with counterparty
        progressTracker.setCurrentStep(INITIATE_SESSION);
        FlowSession issuePartySession = initiateFlow((issuer));
        FlowSession otherPartySession = initiateFlow(carOwner);

        ArrayList<FlowSession> sessions = new ArrayList<>();
        sessions.add(otherPartySession);
        sessions.add(issuePartySession);

        final SignedTransaction fullySignedTx = subFlow(
                new CollectSignaturesFlow(signedTx, sessions, CollectSignaturesFlow.Companion.tracker()));

//        SignedTransaction fullySignedTx = subFlow(new CollectSignaturesFlow(
//                signedTx, Arrays.asList(otherPartySession), CollectSignaturesFlow.tracker()));


        //Finalizing  the transaction
        progressTracker.setCurrentStep(FINALIZE_FLOW);
        subFlow(new FinalityFlow(fullySignedTx,sessions));

        return "Transfer Completed";
    }
}

【问题讨论】:

    标签: java corda


    【解决方案1】:

    您需要为您的线性状态创建第二个构造函数,该构造函数接受linearId 作为输入参数;你应该用注解@ConstructorForDeserialization来标记构造函数。

    否则,当您的流程暂停(出于任何原因)并序列化您的线性状态时,流程将尝试恢复和反序列化状态;它将使用您当前的构造函数,该构造函数生成一个随机的 linearId,因此流程最终会以一个新的/不同的状态结束(因为它有一个不同的linearId)。

    但是当您创建第二个构造函数并用注解标记它时,流程将使用它来反序列化并创建相同的状态。

    您也可以在创建输出状态时使用该构造函数,而不是像现在那样使用 setter。

    编辑(添加流程代码后):

    1. 您不能使用消费状态作为输入;这就是所谓的双花问题。想象一下,你有一个美元国家,你试图用同一个美元两次买东西;那不可能发生。如果您尝试使用消费状态作为输入,公证人将抛出异常。
    2. 这就是为什么当您查询时,您应该查询UNCONSUMED 而不是ALL
    3. 您的查询解决方案不正确且效率不高,想象一下如果您有 100,000 辆汽车;您要获取所有 100,000 个,然后循环遍历它们,直到找到具有所需 VIN 的汽车?首先你需要分页(如果你的结果集返回超过 200 条记录并且你没有使用分页,Corda 会抛出一个错误),其次这可能会耗尽你的 Java 堆来创建这 100,000 个对象并使你的 CorDapp 崩溃。
    4. 相反,您应该为您的汽车状态创建一个自定义架构;然后使用自定义查询条件按 VIN 号查询。查看 IOU 示例,他们如何为 IOU 状态创建自定义模式(请参阅 herehere)。然后您可以在VaultCustomQueryCriteria 中使用自定义架构(阅读here)。

    【讨论】:

    • 所以,按照说明操作,但在传输流中得到 NullPointerException。
    • 如果可能,您可以使用流程的完整代码更新您的问题;那我可以看看。
    • [错误] 00:03:49-0400 [RxIoScheduler-2] internal.GeneralExceptionHandler。 - 线程“RxIoScheduler-2”中的异常 [errorCode=14ajzzg, moreInformationAt=errors.corda.net/OS/4.4/14ajzzg]
    • 我的意思是编辑您的问题并添加流程的完整代码,而不是错误。
    • 我已经在 Flow 下附加了完整的 TransferFlowInitiator
    猜你喜欢
    • 1970-01-01
    • 2011-06-04
    • 2014-01-14
    • 2016-12-13
    • 2018-01-04
    • 2017-02-15
    • 1970-01-01
    • 1970-01-01
    • 2020-09-12
    相关资源
    最近更新 更多