Closed pfi79 closed 1 month ago
Can you perhaps add a stack trace dump in the place where we verify the consenter signature?
easily
goroutine 126 [running]:
github.com/hyperledger/fabric/orderer/consensus/smartbft.(*Verifier).VerifyConsenterSig(0xc000032e80, {0x5, {0xc000447340, 0x6f, 0x6f}, {0xc0009a2b80, 0x77, 0x77}}, {{0xc000c2c000, 0xa5cf, ...}, ...})
/Users/f/go/src/github.com/hyperledger/fabric/orderer/consensus/smartbft/verifier.go:218 0xb14
github.com/hyperledger-labs/SmartBFT/internal/bft.(*View).verifyPrevCommitSignatures(0xc0000f6600, {0xc000e9a240, 0x4, 0x4}, 0x0)
/Users/f/go/src/github.com/hyperledger/fabric/vendor/github.com/hyperledger-labs/SmartBFT/internal/bft/view.go:631 0x7c6
github.com/hyperledger-labs/SmartBFT/internal/bft.(*View).verifyProposal(0xc0000f6600, {{0xc000efe580, 0x75, 0x75}, {0xc00063e230, 0x49, 0x49}, {0xc0009567b0, 0x4, 0x4}, ...}, ...)
/Users/f/go/src/github.com/hyperledger/fabric/vendor/github.com/hyperledger-labs/SmartBFT/internal/bft/view.go:588 0xb45
github.com/hyperledger-labs/SmartBFT/internal/bft.(*View).processProposal(0xc0000f6600)
/Users/f/go/src/github.com/hyperledger/fabric/vendor/github.com/hyperledger-labs/SmartBFT/internal/bft/view.go:386 0x5e5
github.com/hyperledger-labs/SmartBFT/internal/bft.(*View).doPhase(0xc0000f6600)
/Users/f/go/src/github.com/hyperledger/fabric/vendor/github.com/hyperledger-labs/SmartBFT/internal/bft/view.go:291 0x46
github.com/hyperledger-labs/SmartBFT/internal/bft.(*View).run(0xc0000f6600)
/Users/f/go/src/github.com/hyperledger/fabric/vendor/github.com/hyperledger-labs/SmartBFT/internal/bft/view.go:277 0x215
github.com/hyperledger-labs/SmartBFT/internal/bft.(*View).Start.func1()
/Users/f/go/src/github.com/hyperledger/fabric/vendor/github.com/hyperledger-labs/SmartBFT/internal/bft/view.go:140 0x1c
created by github.com/hyperledger-labs/SmartBFT/internal/bft.(*View).Start in goroutine 85
/Users/f/go/src/github.com/hyperledger/fabric/vendor/github.com/hyperledger-labs/SmartBFT/internal/bft/view.go:139 0x20d
In the very first stage of consensus, the smartBFT library takes the previous commit with signatures and checks for correctness.
If I remember correctly, we only add the previous signatures, when we have leader rotation enabled, and in Fabric we don't have leader rotation enabled. If the leader doesn't send the previous signatures, then the followers won't verify them.
However in the tests, the decisions per leader is 0... it is therefore odd that the previous signatures verification is the cause this behavior.
Can you perhaps add a stack trace dump in the place where we verify the consenter signature?
Just to give some background - we introduced the previous commit signatures in order to know how to prune the blacklist. However, we don't use leader rotation nor the blacklist in Fabric, so before we go ahead and fix something, let's be 100% sure of it's cause.
My suggestion for a fix:
- keep the previous set of nodes in memory
- if we don't find a signature in the current set and the block is equal and/or less than the current block number, check in the previous set
Regarding your fix - I don't think we should leniently just check the previous set if we don't find a signature in the current set. Moreover, in your commit, you check the previous set if you don't find an identity, and not a signature. This function is used also to collect commit messages, so we should not carelessly change it like this.
I think there is a more "holistic" fix:
- When verifying a block, we inspect the Fabric header number and look at the block number. If the last block we have committed (we check the runtime config) is the previous block to the block we're verifying, then we proceed as usual.
- Else, if it is a block we have not committed yet (I know this is not possible, but for completeness, I am writing this case) we return an error.
- Else, it's a block from the past, so we fetch the block with this number from the ledger, and look at its last config block. We then fetch that config block, and proceed to use it, to verify the requested signature.
The above "fix" is very easy to test, as it only changes a single function and preserves the intended verification logic.
error itself:
2024-10-11 15:32:51.289 MSK 181e WARN [orderer.consensus.smartbft.consensus] processProposal -> 1 received bad proposal from 1: failed verifying consenter signature of 5: node with id of 5 doesn't exist channel=testchannel
In the very first stage of consensus, the smartBFT library takes the previous commit with signatures and checks for correctness.
If I remember correctly, we only add the previous signatures, when we have leader rotation enabled, and in Fabric we don't have leader rotation enabled. If the leader doesn't send the previous signatures, then the followers won't verify them. However in the tests, the decisions per leader is 0... it is therefore odd that the previous signatures verification is the cause this behavior. Can you perhaps add a stack trace dump in the place where we verify the consenter signature? Just to give some background - we introduced the previous commit signatures in order to know how to prune the blacklist. However, we don't use leader rotation nor the blacklist in Fabric, so before we go ahead and fix something, let's be 100% sure of it's cause.
My suggestion for a fix:
- keep the previous set of nodes in memory
- if we don't find a signature in the current set and the block is equal and/or less than the current block number, check in the previous set
Regarding your fix - I don't think we should leniently just check the previous set if we don't find a signature in the current set. Moreover, in your commit, you check the previous set if you don't find an identity, and not a signature. This function is used also to collect commit messages, so we should not carelessly change it like this. I think there is a more "holistic" fix:
- When verifying a block, we inspect the Fabric header number and look at the block number. If the last block we have committed (we check the runtime config) is the previous block to the block we're verifying, then we proceed as usual.
- Else, if it is a block we have not committed yet (I know this is not possible, but for completeness, I am writing this case) we return an error.
- Else, it's a block from the past, so we fetch the block with this number from the ledger, and look at its last config block. We then fetch that config block, and proceed to use it, to verify the requested signature.
The above "fix" is very easy to test, as it only changes a single function and preserves the intended verification logic.
error itself:
2024-10-11 15:32:51.289 MSK 181e WARN [orderer.consensus.smartbft.consensus] processProposal -> 1 received bad proposal from 1: failed verifying consenter signature of 5: node with id of 5 doesn't exist channel=testchannel
Total:
Regarding your fix - I don't think we should leniently just check the previous set if we don't find a signature in the current set. Moreover, in your commit, you check the previous set if you don't find an identity, and not a signature. This function is used also to collect commit messages, so we should not carelessly change it like this.
I think there is a more "holistic" fix:
- When verifying a block, we inspect the Fabric header number and look at the block number. If the last block we have committed (we check the runtime config) is the previous block to the block we're verifying, then we proceed as usual.
- Else, if it is a block we have not committed yet (I know this is not possible, but for completeness, I am writing this case) we return an error.
- Else, it's a block from the past, so we fetch the block with this number from the ledger, and look at its last config block. We then fetch that config block, and proceed to use it, to verify the requested signature.
The above "fix" is very easy to test, as it only changes a single function and preserves the intended verification logic.
I have the block number check.
Do you want me to get the config and participant set in the same place?
I don't think we should be sending the previous commit signatures if we don't need them. Why do that? It's just excess CPU cycles, network bandwidth and disk storage.
I think we should not attach them if leader rotation is disabled.
I don't think we should be sending the previous commit signatures if we don't need them. Why do that? It's just excess CPU cycles, network bandwidth and disk storage.
I think we should not attach them if leader rotation is disabled.
What if at the time the 5th node is removed, the leader is the 5th node?
and we'll be in the same situation again
I don't think we should be sending the previous commit signatures if we don't need them. Why do that? It's just excess CPU cycles, network bandwidth and disk storage. I think we should not attach them if leader rotation is disabled.
What if at the time the 5th node is removed, the leader is the 5th node?
- leader change
- the previous signatures would be
- The 5th node can participate.
and we'll be in the same situation again
If we're not attaching signatures of the previous block then how can we have a problem in verifying the signatures of the previous block which we do not attach?
I don't think we should be sending the previous commit signatures if we don't need them. Why do that? It's just excess CPU cycles, network bandwidth and disk storage. I think we should not attach them if leader rotation is disabled.
What if at the time the 5th node is removed, the leader is the 5th node?
- leader change
- the previous signatures would be
- The 5th node can participate.
and we'll be in the same situation again
If we're not attaching signatures of the previous block then how can we have a problem in verifying the signatures of the previous block which we do not attach?
during the change of leadership?
I don't think we should be sending the previous commit signatures if we don't need them. Why do that? It's just excess CPU cycles, network bandwidth and disk storage. I think we should not attach them if leader rotation is disabled.
What if at the time the 5th node is removed, the leader is the 5th node?
- leader change
- the previous signatures would be
- The 5th node can participate.
and we'll be in the same situation again
If we're not attaching signatures of the previous block then how can we have a problem in verifying the signatures of the previous block which we do not attach?
Or is it only needed when rotation is on? and when rotation is disabled it is not necessary, even when the leader has changed?
exactly, it's only used when periodical leader rotation is active. A regular leader failover has nothing to do with it.
exactly, it's only used when periodical leader rotation is active. A regular leader failover has nothing to do with it.
Okay. then I'll refine the task. to leave adding signatures of the previous comitee only if leader rotation is enabled and DecisionsInView==0
right?
exactly, it's only used when periodical leader rotation is active. A regular leader failover has nothing to do with it.
Okay. then I'll refine the task. to leave adding signatures of the previous comitee only if leader rotation is enabled and DecisionsInView==0
right?
I don't understand how decisions in view is related to what we're talking about. Did you mean DecisionsPerLeader?
I don't understand how decisions in view is related to what we're talking about. Did you mean DecisionsPerLeader?
DecisionsPerLeader > 0 - indicator that rotation is enabled
DecisionsInView==0 - indicator that the leader has just been changed Or is the second one unnecessary?
I don't understand how decisions in view is related to what we're talking about. Did you mean DecisionsPerLeader?
DecisionsPerLeader > 0 - indicator that rotation is enabled
DecisionsInView==0 - indicator that the leader has just been changed Or is the second one unnecessary?
The former is a configuration parameter. The latter is a byproduct of the consensus protocol.
So we need to consider the former, not the latter.
I don't understand how decisions in view is related to what we're talking about. Did you mean DecisionsPerLeader?
DecisionsPerLeader > 0 - indicator that rotation is enabled DecisionsInView==0 - indicator that the leader has just been changed Or is the second one unnecessary?
The former is a configuration parameter. The latter is a byproduct of the consensus protocol.
So we need to consider the former, not the latter.
https://github.com/hyperledger-labs/SmartBFT/pull/599
take a look, please.
fixed an error after deleting a node when it participated in block signing immediately before deletion
Recently the TestAddAndRemoveNodeWithoutStop test has been terminating with an error very often in unit tests.
It went like this:
My suggestion for a fix:
Perhaps there is a better and more beautiful solution.