Контракты не могут быть удовлетворены заполнителем AutomaticPlaceholderConstraint - PullRequest
0 голосов
/ 25 октября 2019

Приложение My Corda состоит из одного Contract, двух OwnableStates Инициатора FlowLogic и Ответчика FlowLogic. Транзакция, которую я пытаюсь сформировать, имеет два входа и два выхода. Один вход должен быть активом, а другой - валютой, для которой я создал собственную OwnableState.

Я добавил следующие входы и выходы в построитель транзакций:

TransactionBuilder txBuilder = new TransactionBuilder(notary);
        txBuilder.addInputState(new StateAndRef<AssetState>(new TransactionState<AssetState>(inputAsset, notary), new StateRef(SecureHash.sha256("com.template.contracts.Contract"), 0)));
        txBuilder.addInputState(new StateAndRef<CurrencyState>(new TransactionState<CurrencyState>(inputCurrency, notary), new StateRef(SecureHash.sha256("com.template.contracts.ContractCurrency"), 1)));
        txBuilder.addOutputState(outputAsset, notary);
        txBuilder.addOutputState(outputCurrency, notary);
        txBuilder.addCommand(command);

Единственное различие между состояниями ввода и вывода - владельцы. И валюта, и состояние актива принадлежат одному контракту. Логика проверки этого контракта показана ниже:

 @Override    
    public void verify(LedgerTransaction tx) {

        List<InOutGroup<AssetState, AssetState>> AssetGroups = tx.groupStates(AssetState.class, AssetState::withoutOwner);
        List<InOutGroup<CurrencyState, CurrencyState>> CurrencyGroups = tx.groupStates(CurrencyState.class, CurrencyState::withoutOwner);
        CommandWithParties<Commands> cmd = requireSingleCommand(tx.getCommands(), Commands.class);

        for (InOutGroup AssetGroup : AssetGroups) {
            List<AssetState> AssetInputs = AssetGroup.getInputs();
            List<AssetState> AssetOutputs = AssetGroup.getOutputs();

            AssetState AssetInput = AssetsInputs.get(0);
            if (cmd.getValue() instanceof Commands.Transfer) {
                requireThat(require -> {
                        require.using("the transaction is signed by the owner of the Asset", cmd.getSigners().contains(AssetInput.getOwner().getOwningKey()));
                        return null;
                }); 
            } else {
                throw new IllegalArgumentException("Unrecognised command");
            } 

            for (InOutGroup CurrencyGroup : CurrencyGroups) {
                List<CurrencyState> CurrencyInputs = CurrencyGroup.getInputs();
                List<CurrencyState> CurrencyOutputs = CurrencyGroup.getOutputs();

                if (cmd.getValue() instanceof Commands.Transfer) {
                    CurrencyState CurrencyInput = CurrencyInputs.get(0);
                    requireThat(require -> {
                        require.using("the transaction is signed by the owner of the Currency", cmd.getSigners().contains(CurrencyInput.getOwner().getOwningKey()));
                        return null;
                    }); 
                } else {
                    throw new IllegalArgumentException("Unrecognised command");
            }
        }
    }}

При выполнении TransactionFlow в терминале я получаю сообщение об ошибке:

Contracts cannot be satisfied by an AutomaticPlaceholderConstraint placeholder.

Я не смог найти в Интернете ничего, чтомне помогает, и я не уверен, где искать ошибку. Поэтому я был бы признателен за вашу помощь. Спасибо!

Отказ от ответственности: я изменил имена классов и переменных, чтобы их было легче понять. Если в именах есть опечатка, пожалуйста, игнорируйте ее. Я уверен, что это не проблема;).

Ответы [ 2 ]

0 голосов
/ 12 ноября 2019

Я думаю, что проблема в том, как вы строите транзакцию. Входными данными для транзакции должно быть состояние, доступное в настоящее время в бухгалтерской книге.

Учитывая приведенный ниже фрагмент кода для добавления состояния ввода в транзакцию:

txBuilder.addInputState(new StateAndRef<AssetState>(new TransactionState<AssetState>(inputAsset, notary), new StateRef(SecureHash.sha256("com.template.contracts.Contract"), 0)));

Метод addInputState принимает объект StateAndRef, часть состояния в порядке, но ссылка является ссылкой на транзакцию, которая создала состояние, поэтому второй параметр метода, который является StateRef, должен содержать trnxId и output_index. В вашем случае SecureHash - это не trnxId, а хэш sha256 строки "com.template.contracts.Contract".

Более простой способ добавить входные данные в транзакцию - этопередать результат vaultQuery напрямую. VaultQuery возвращает объект StateAndRef, который можно передать в качестве параметра методу addInputState. Например:

getServiceHub().getVaultService().queryBy(SampleState.class)
    .getStates().stream()
    // Filter based on field value "XYZ"
    .filter(sampleStateAndRef -> {
        SampleState sampleState = sampleStateStateAndRef.getState().getData();
                return sampleState.getField().equals("XYZ");
        }).findAny().orElseThrow(() -> new FlowException("State Not Found"));

Надеюсь, это поможет!

0 голосов
/ 04 ноября 2019

У нас есть три типа ограничений - HashConstraint, WhiteListListedByZone, Signature . Когда мы создаем состояние ввода в первый раз, оно связывается с одним из ограничений. Когда вы создаете транзакцию, добавляя в нее входные и выходные состояния, и если вы явно не указали, какое ограничение использовать для выходного состояния, ограничение входного состояния распространяется на выходное состояние. В таком случае AutomaticPlaceholderConstraint используется по умолчанию при создании транзакции, поскольку вы явно не указали ограничение. Какое выходное ограничение использовать, оценивается и присваивается выходному состоянию. Иногда он не может оценить правильное ограничение выходного состояния, и именно тогда он генерирует исключение. Я думаю, что это то, что происходит с вашим делом. Не могли бы вы вставить дополнительные журналы, которые могли бы помочь мне понять больше.

Некоторые ситуации, которые не будут работать, например -
Входные состояния с использованием HashConstraint или WhiteListByZoneConstraint, выходные состояния пытаются использовать ограничение подписи

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...