【问题标题】:Hyperledger Fabric Chaincode throws MVCC_READ_CONFLICTHyperledger Fabric 链码抛出 MVCC_READ_CONFLICT
【发布时间】:2023-05-13 16:02:01
【问题描述】:

我在调用链码函数时遇到错误。我为该功能创建了两个改编版本。一个使用常规键,另一个使用复合键。我认为使用复合键可以解决任何 MVCC_READ_CONFLICT,因为我不再更新同一个键。

但是,我在这两个函数上都遇到了错误。请注意,这两个函数都包含在同一个链码中。我不知道这是否会导致冲突。

下面是带有普通键的函数:

    func (*AddTokenCallFunction) Start(stub shim.ChaincodeStubInterface, args []string) pb.Response {
        if len(args) != 2 {
            s := fmt.Sprintf(ERROR_INCORRECT_AMOUNT_OF_ARGUMENTS, "add-tokens", 2, len(args))
            return shim.Error(s)
        }

        account := args[0]
        tokens := args[1]

        currentTokensBytes, err := stub.GetState(account)
        if err != nil {
            s := fmt.Sprintf(ERROR_SYSTEM, err.Error())
            return shim.Error(s)
        }
        currentAmountOfTokens := binary.LittleEndian.Uint64(currentTokensBytes)
        tokensToAdd, err := strconv.ParseUint(tokens, 10, 64)
        if err != nil {
            s := fmt.Sprintf(ERROR_SYSTEM, err.Error())
            return shim.Error(s)
        }
        currentAmountOfTokens += tokensToAdd
        tokenBytes, err := UintToBytes(currentAmountOfTokens)
        if err != nil {
            s := fmt.Sprintf(ERROR_SYSTEM, err.Error())
            return shim.Error(s)
        }
        err = stub.PutState(account, tokenBytes)
        if err != nil {
            s := fmt.Sprintf(ERROR_SYSTEM, err.Error())
            return shim.Error(s)
        }

        return shim.Success(nil)
    }

这是相同的功能,但带有复合键:

func (*AddTokenCompositeCallFunction) Start(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    if len(args) != 2 {
        s := fmt.Sprintf(ERROR_INCORRECT_AMOUNT_OF_ARGUMENTS, "add-composite-tokens", 2, len(args))
        return shim.Error(s)
    }

    account := args[0]
    tokens := args[1]

    // Retrieve info needed for the update procedure
    txid := stub.GetTxID()
    compositeIndexaccount := "account~tokens~txID"

    // Create the composite key that will allow us to query for all deltas on a particular variable
    compositeKey, compositeErr := stub.CreateCompositeKey(compositeIndexaccount, []string{account, tokens, txid})
    if compositeErr != nil {
        return shim.Error(fmt.Sprintf("Could not create a composite key for %s: %s", account, compositeErr.Error()))
    }

    // Save the composite key index
    compositePutErr := stub.PutState(compositeKey, []byte{0x00})
    if compositePutErr != nil {
        return shim.Error(fmt.Sprintf("Could not put operation for %s in the ledger: %s", account, compositePutErr.Error()))
    }

    return shim.Success([]byte(fmt.Sprintf("Successfully added %s to %s", tokens, account)))
}

有人可以解释为什么我在以后的实现中仍然会收到 MVCC_READ_CONFLICT 吗?我究竟做错了什么?我多次进行基准测试并发送相同的 accountID。虽然我的印象是使用复合键时这无关紧要。

提前致谢。

【问题讨论】:

  • 第二个实现对我来说看起来不错,因为事务 id 保证是唯一的。您确定您删除了旧的链码图像并重试了吗?
  • @arnabkaycee 我在 GCE 中运行,昨天我删除了所有实例,包括它们的磁盘。我尝试了 fabric-samples repo 中的高吞吐量示例,并且该示例运行正常。所以我想这与我的实现有关。即使我的实现基于高通量样本。
  • 确保避免在一个块中多次修改同一个键。

标签: hyperledger-fabric hyperledger


【解决方案1】:

我通过删除自己的实现并将其替换为高吞吐量示例 [https://github.com/hyperledger/fabric-samples/blob/release/high-throughput/chaincode/high-throughput.go] 中的实现来解决此问题。

我的猜测是我在我的实现中做了一些 Golang 不同意的事情。因为实现并没有那么不同。

【讨论】: