Hyperledger composer:在更新资产 returns 旧结果的交易中调用查询

Hyperledger composer: calling a query within a transaction that updated an asset returns old results

我有一个非常简单的 Hyperledger Composer 应用程序命名空间的问题 com.softwaremill.drivernetwork

participant Driver identified by licenseId {
  o String licenseId
  o String firstName
  o String lastName
  o Boolean licenseValid default =true
}

enum LaweEnforcerType {
  o POLICE
  o CUSTOMS
  o BORDER_GUARDS
}

participant LawEnforcer identified by lawEnforcerId {
  o String lawEnforcerId
  o LaweEnforcerType lawEnforcerType
}

participant Court identified by courtId {
  o String courtId
  o String description
}

enum FineState {
  o ISSUED
  o REJECTED
  o ACCEPTED
}

asset Fine identified by fineId {
  o String fineId
  o Integer penaltyPoints
  o DateTime date
  o FineState fineState default ="ISSUED"
  --> Driver driver
  --> LawEnforcer lawEnforcer
}

asset CourtCase identified by caseId {
  o String caseId
  --> Court court optional
  --> Fine fine
}

transaction AcceptedFine {
  --> Fine fine
}

transaction RejectedFine {
  --> Fine fine
}

LawEnforcer 可以处以罚款。 driver.

可以接受或拒绝罚款(然后上法庭)

我想做的是,如果 driver 接受的所有 penaltyPoints 罚款总和超过 20 点,则自动使他的执照失效。

所以我创建了一个交易处理器

/**
 * Accept fine
 * @param {com.softwaremill.drivernetwork.AcceptedFine} acceptedFine
 * @transaction
 */
async function acceptedFine(acceptedFine) {
    console.log(`Accepting fine ${acceptedFine}`);

    const fineRegistry = await     getAssetRegistry('com.softwaremill.drivernetwork.Fine');

    acceptedFine.fine.fineState = 'ACCEPTED';
    await fineRegistry.update(acceptedFine.fine); // [1]

    const allFines = await query('selectAcceptedFinesByDriver', 
    {driver: `resource:com.softwaremill.drivernetwork.Driver#${acceptedFine.fine.driver.licenseId}`}); // [2]

    if (allFines.reduce((acc, val) => {return acc + val.penaltyPoints;}, 0) > 20) {
        console.log('Driver excceded 20 points, blocking license');

        const driverRegistry = await getParticipantRegistry('com.softwaremill.drivernetwork.Driver');

        acceptedFine.fine.driver.licenseValid = false;

        await driverRegistry.update(acceptedFine.fine.driver);
    }
}

以及查询码

query selectAcceptedFinesByDriver {
  description: "Select all accepted fines for a given driver"
  statement:
    SELECT com.softwaremill.drivernetwork.Fine
      WHERE (driver == _$driver AND fineState == "ACCEPTED")
}

现在代码应该在 [1] 处将 Fine 状态设置为 ACCEPTED。这有效 - 处理交易后,我可以看到 属性 已更改。

但问题是在 [2] 执行查询时,刚刚在 [1] 更新的 Fine 仍然处于 ISSUED 状态(我已经删除了正确的部分在查询中调试它的位置)。

我在这里错过了什么?区块链的形状有人为交易冻结吗?怎么回事?

问题是你不能"read your own writes"。事务是原子的(因此在一个事务中更改的所有状态都作为一个事务从当前状态提交,或者 - 整个事务被拒绝。

所以您正在阅读(在查询中)的 'state' 是上次提交状态的已知状态(当前事务尚未提交,因此 [2] 不可能在该点获取 'ACCEPTED' 状态。Composer 中的此行为与您从底层 Hyperledger Fabric 区块链获得的行为完全相同;GetState(query) 将仅读取已提交的状态更改,而不是数据(在当前事务中)由先前的PutState(同一事务中的先前更新)编写。查询仅在该事务已经提交时才有效(在这种情况下),即由组织的同行提交endorse/commit 交易(原子交易)到一个区块(和世界状态)。

您可以在此处阅读有关交易处理器的更多信息 -> https://hyperledger.github.io/composer/latest/reference/js_scripts

您没有更新资产的 Fine 状态,您只是在提交的交易上这样做。

您需要像更新 licenseValid 状态一样在资产上更新它。