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 状态一样在资产上更新它。
我有一个非常简单的 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 状态一样在资产上更新它。