-
Notifications
You must be signed in to change notification settings - Fork 296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Occasionally got "Block submitted via getwork does not meet the required proof of work" when submit a work #1566
Comments
I think I need a temporary fix to reduce the loss of mining reward. If anyone has any suggestions for mitigating or fixing the problem, please feel free to submit it to me. The most important thing for me is that the problem can be mitigating and my block can be broadcasted to the network. I don't very care security or code quality (for me, there is not much loss in broadcasting an invalid block, but losing a valid block is a big loss in money.) |
Thanks for the report. We'll dig in a bit to see if we can reproduce and/or spot the issue. To clarify something though, I noticed you said you have two nodes. Are you sure that you are submitting the solution back to the specific node that provided the work? The reason I ask is because the way that |
In my implementation, I will submit to both nodes at the same time. And this should be the response of the node that does not match the work:
So the other is the matched node:
|
In // Create the new merkleRootPair key which is MerkleRoot + StakeRoot
var merkleRootPair [merkleRootPairSize]byte
copy(merkleRootPair[:chainhash.HashSize], submittedHeader.MerkleRoot[:])
copy(merkleRootPair[chainhash.HashSize:], submittedHeader.StakeRoot[:])
// Look up the full block for the provided data based on the merkle
// root. Return false to indicate the solve failed if it's not
// available.
blockInfo, ok := s.templatePool[merkleRootPair]
if !ok {
rpcsLog.Errorf("Block submitted via getwork has no matching "+
"template for merkle root %s",
submittedHeader.MerkleRoot)
return false, nil
} The program did not return here, proving that both MerkleRoot and StakeRoot in the submission match the node's work. The following codes: // Reconstruct the block using the submitted header stored block info.
// A temporary block is used because we will be mutating the contents
// for the construction of the correct regular merkle tree. You must
// also deep copy the block itself because it could be accessed outside
// of the GW workstate mutexes once it gets submitted to the
// blockchain.
tempBlock := dcrutil.NewBlockDeepCopy(blockInfo.msgBlock)
msgBlock := tempBlock.MsgBlock()
msgBlock.Header = submittedHeader
if msgBlock.Header.Height > 1 {
pkScriptCopy := make([]byte, len(blockInfo.pkScript))
copy(pkScriptCopy, blockInfo.pkScript)
msgBlock.Transactions[0].TxOut[1].PkScript = blockInfo.pkScript
merkles := blockchain.BuildMerkleTreeStore(tempBlock.Transactions())
msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]
}
// The real block to submit, with a proper nonce and extraNonce.
block := dcrutil.NewBlockDeepCopyCoinbase(msgBlock)
// Ensure the submitted block hash is less than the target difficulty.
err = blockchain.CheckProofOfWork(&block.MsgBlock().Header,
activeNetParams.PowLimit)
if err != nil {
// Anything other than a rule violation is an unexpected error,
// so return that error as an internal error.
if _, ok := err.(blockchain.RuleError); !ok {
return false, rpcInternalError("Unexpected error "+
"while checking proof of work: "+err.Error(),
"")
}
rpcsLog.Errorf("Block submitted via getwork does not meet "+
"the required proof of work: %v", err)
return false, nil
} I guess if no |
Yesterday the problem appeared again: submitblock request: {"jsonrpc":"1.0","id":"1","method":"getwork","params":["050000007a97064f8f4c0d0a9bae925482673562d593a4797719ac340000000000000000817374720fb2413085b8a0457ab32b86a91eb73bd57d188d6a7df7f81331b822bed67ee4b32b150c1822b60f62098744777859e667ab79144286a2c0c46faec501008f61701b18be05000600f49f00005961461876a3138e020000001bb50400ef390000268d375cbfc2844a443c050000f429ce989766030000000000000000000000000000000000000000050000008000000100000000000005a0"]} One node log (not matched, normal):
The other log (matched, abnormal):
But the hash should be |
decred/gominer used to see that. does your code have this similar check? https://github.com/decred/gominer/blob/master/device.go#L283 |
Yes, my code will compute the hash by itself. For this submittion: {"jsonrpc":"1.0","id":"1","method":"getwork","params":["050000007a97064f8f4c0d0a9bae925482673562d593a4797719ac340000000000000000817374720fb2413085b8a0457ab32b86a91eb73bd57d188d6a7df7f81331b822bed67ee4b32b150c1822b60f62098744777859e667ab79144286a2c0c46faec501008f61701b18be05000600f49f00005961461876a3138e020000001bb50400ef390000268d375cbfc2844a443c050000f429ce989766030000000000000000000000000000000000000000050000008000000100000000000005a0"]} My code outputed its hash And in func TestBlockHeaderHashing(t *testing.T) {
dummyHeader := "050000007a97064f8f4c0d0a9bae925482673562d593a4797719ac340000000000000000817374720fb2413085b8a0457ab32b86a91eb73bd57d188d6a7df7f81331b822bed67ee4b32b150c1822b60f62098744777859e667ab79144286a2c0c46faec501008f61701b18be05000600f49f00005961461876a3138e020000001bb50400ef390000268d375cbfc2844a443c050000f429ce989766030000000000000000000000000000000000000000050000008000000100000000000005a0"
// This hash has reversed endianness compared to what chainhash spits out.
hashStr := "b104f3312bd870f9e27447965f0ee9958bbc567c9e6ad9010000000000000000"
hashB, _ := hex.DecodeString(hashStr)
hash, _ := chainhash.NewHash(hashB)
vecH, _ := hex.DecodeString(dummyHeader)
r := bytes.NewReader(vecH)
var bh BlockHeader
bh.Deserialize(r)
hash2 := bh.BlockHash()
if !hash2.IsEqual(hash) {
t.Errorf("wrong block hash returned (want %v, got %v)", hash,
hash2)
}
} It past. But I got this from
So this is obviously a problem in |
@YihaoPeng looking into it, will keep you posted. |
@YihaoPeng build this pr from source #1567 and run your pool with it, it should resolve the issue. |
Any updates on if #1567 resolves the issue as expected? |
Thank you very much. I will try the patch you provided. And the following log comes from a unpatched dcrd v1.4.0-rc1 (without #1567), I only added a line of log (YihaoPeng@27705d4):
It may be helpful in finding the cause of the bug. |
@YihaoPeng Any rejections with the diff yet? |
Resolved by #1567. |
In some cases, you may get an error when you submit a mined block via getwork RPC:
For example, my application call
getwork
RPC with this params:Then I got this as response:
Then
dcrd
recorded this in its log:But when I compute the hash of the submission, I got
00000000000000b0d1016a2bcf905d1149dbead9396ee37e44075eb7eb5cb1dc
. I done it by adding a new testcase towire/blockheader_test.go
:It should be a valid block header with nonce, but dcrd rejected it.
This problem does not always happen, and in most cases everything is fine.
But it does reproduce stably. The problem occurred 8 times in two months (So I lost 8 mined blocks).
I have not noticed this issue until last week. So last week I upgraded dcrd from 1.2 to 1.4.0-rc1. But just yesterday, the problem reappeared.
I suspect that dcrd has some kind of race condition problem. The merkle root calculated when checking the difficulty is different from the work creation, which causes the block hash to completely mismatch.
About my deploy:
I have two
dcrd
running in docker, there arev1.2.0
at first (Dockerfile). Last week, I upgraded them to 1.4.0rc1 (Dockerfile). All of them binaries from https://github.com/decred/decred-binaries.About the issue:
My pool submit about 20 blocks per day to two
dcrd
(about 10 blocks for each). Up to now, there have been 4 such problems with each dcrd (total 8 blocks). Each interval is as short as three days and as long as 12 days. It happened looks like completely random.I use this pool code: https://github.com/btccom/btcpool/
The text was updated successfully, but these errors were encountered: