diff --git a/src/avalanche/proof.h b/src/avalanche/proof.h --- a/src/avalanche/proof.h +++ b/src/avalanche/proof.h @@ -55,7 +55,7 @@ bool isCoinbase() const { return height & 1; } const CPubKey &getPubkey() const { return pubkey; } - uint256 getHash(const ProofId &proofid) const; + uint256 getHash(const ProofIdForStakeSignature &proofid) const; }; class SignedStake { @@ -72,7 +72,7 @@ const Stake &getStake() const { return stake; } const SchnorrSig &getSignature() const { return sig; } - bool verify(const ProofId &proofid) const; + bool verify(const ProofIdForStakeSignature &proofid) const; }; class Proof { @@ -82,6 +82,7 @@ std::vector stakes; LimitedProofId limitedProofId; + ProofIdForStakeSignature proofIdForStakeSignature; ProofId proofid; void computeProofId(); @@ -109,6 +110,9 @@ const ProofId &getId() const { return proofid; } const LimitedProofId &getLimitedId() const { return limitedProofId; } + const ProofIdForStakeSignature &getIdForStakeSignature() const { + return proofIdForStakeSignature; + } uint32_t getScore() const; bool verify(ProofValidationState &state) const; diff --git a/src/avalanche/proof.cpp b/src/avalanche/proof.cpp --- a/src/avalanche/proof.cpp +++ b/src/avalanche/proof.cpp @@ -17,14 +17,14 @@ namespace avalanche { -uint256 Stake::getHash(const ProofId &proofid) const { +uint256 Stake::getHash(const ProofIdForStakeSignature &proofid) const { CHashWriter ss(SER_GETHASH, 0); ss << proofid; ss << *this; return ss.GetHash(); } -bool SignedStake::verify(const ProofId &proofid) const { +bool SignedStake::verify(const ProofIdForStakeSignature &proofid) const { return stake.getPubkey().VerifySchnorr(stake.getHash(proofid), sig); } @@ -59,6 +59,12 @@ limitedProofId = LimitedProofId(ss.GetHash()); proofid = limitedProofId.computeProofId(master); + + CHashWriter ss2(SER_GETHASH, 0); + ss2 << sequence; + ss2 << expirationTime; + ss2 << master; + proofIdForStakeSignature = ProofIdForStakeSignature(ss2.GetHash()); } uint32_t Proof::getScore() const { @@ -96,7 +102,7 @@ "duplicated-stake"); } - if (!ss.verify(proofid)) { + if (!ss.verify(proofIdForStakeSignature)) { return state.Invalid(ProofValidationResult::INVALID_SIGNATURE, "invalid-signature"); } diff --git a/src/avalanche/proofbuilder.h b/src/avalanche/proofbuilder.h --- a/src/avalanche/proofbuilder.h +++ b/src/avalanche/proofbuilder.h @@ -24,7 +24,7 @@ StakeSigner(Stake stake_, CKey key_) : stake(std::move(stake_)), key(std::move(key_)) {} - SignedStake sign(const ProofId &proofid); + SignedStake sign(const ProofIdForStakeSignature &proofid); }; std::vector stakes; @@ -46,7 +46,7 @@ static Proof buildRandom(uint32_t score); private: - ProofId getProofId() const; + ProofIdForStakeSignature getProofIdForSigning() const; }; } // namespace avalanche diff --git a/src/avalanche/proofbuilder.cpp b/src/avalanche/proofbuilder.cpp --- a/src/avalanche/proofbuilder.cpp +++ b/src/avalanche/proofbuilder.cpp @@ -8,7 +8,8 @@ namespace avalanche { -SignedStake ProofBuilder::StakeSigner::sign(const ProofId &proofid) { +SignedStake +ProofBuilder::StakeSigner::sign(const ProofIdForStakeSignature &proofid) { const uint256 h = stake.getHash(proofid); SchnorrSig sig; @@ -32,7 +33,7 @@ } Proof ProofBuilder::build() { - const ProofId proofid = getProofId(); + const ProofIdForStakeSignature proofid = getProofIdForSigning(); std::vector signedStakes; signedStakes.reserve(stakes.size()); @@ -46,21 +47,13 @@ std::move(signedStakes)); } -ProofId ProofBuilder::getProofId() const { +ProofIdForStakeSignature ProofBuilder::getProofIdForSigning() const { CHashWriter ss(SER_GETHASH, 0); ss << sequence; ss << expirationTime; + ss << master; - WriteCompactSize(ss, stakes.size()); - for (const auto &s : stakes) { - ss << s.stake; - } - - CHashWriter ss2(SER_GETHASH, 0); - ss2 << ss.GetHash(); - ss2 << master; - - return ProofId(ss2.GetHash()); + return ProofIdForStakeSignature(ss.GetHash()); } Proof ProofBuilder::buildRandom(uint32_t score) { diff --git a/src/avalanche/proofid.h b/src/avalanche/proofid.h --- a/src/avalanche/proofid.h +++ b/src/avalanche/proofid.h @@ -14,6 +14,10 @@ namespace avalanche { +/** + * This is a hash of the entire proof, providing a unique identifier. This + * is what is used for proof inventories. + */ struct ProofId : public uint256 { explicit ProofId() : uint256() {} explicit ProofId(const uint256 &b) : uint256(b) {} @@ -25,6 +29,10 @@ } }; +/** + * This is a hash of the proof excluding the proof master key. + * It is used by the delegation. + */ struct LimitedProofId : public uint256 { explicit LimitedProofId() : uint256() {} explicit LimitedProofId(const uint256 &b) : uint256(b) {} @@ -38,6 +46,18 @@ ProofId computeProofId(const CPubKey &proofMaster) const; }; +/** + * This hash is used for the signatures associated with each stake. It is a + * proof ID that covers the Proof data excluding the stakes. This allows for + * additional stakes to be added to an existing proof without recomputing the + * signature for all other stakes, making collaborative proof building + * simpler. + */ +struct ProofIdForStakeSignature : public uint256 { + explicit ProofIdForStakeSignature() : uint256() {} + explicit ProofIdForStakeSignature(const uint256 &b) : uint256(b) {} +}; + class SaltedProofIdHasher : private SaltedUint256Hasher { public: SaltedProofIdHasher() : SaltedUint256Hasher() {} diff --git a/src/avalanche/test/proof_tests.cpp b/src/avalanche/test/proof_tests.cpp --- a/src/avalanche/test/proof_tests.cpp +++ b/src/avalanche/test/proof_tests.cpp @@ -159,9 +159,9 @@ "02512eea4ba32a6d6672767be4959c0f70489b803a47a3abf83f30e8d9da978de4027" "c70ce7e0d3b0ad62eb08edd8f90169a79ff23e1d58c64afad42ad81cffe53967e16be" "b692fc5776bb442c79c5d91de00cf21804712806594010038e168a32102449fb5237e" - "fe8f647d32e8b64f06c22d1d40368eaca2a71ffc6a13ecc8bce6800a7b4811c6412ad" - "f94b0d6bb5227aeec27f49b2948b6e3da564d12d96ff00779f113d52c82093e101323" - "4440ad829030c685ca03d4fd9ce95b298e79c5eee6e2", + "fe8f647d32e8b64f06c22d1d40368eaca2a71ffc6a13ecc8bce680891fe414ab8b2cb" + "c63741f1a9ea06cc496b4fe37a39eef2cdc97cf8c1efdd3ba074ba21bfaa419a7d3da" + "96e9d4c55e7501954ee1f4bf0d16dc94bf4dea9d81d8", ProofId::fromHex("cbd77dad2ebc525c591ab44a0f6a25803c1d934c3e5caa61f9f4" "c63c9f29a4e6"), 444638638, ProofValidationResult::NONE}, @@ -169,13 +169,13 @@ "60f8332a3ff3430a4f3c9010160cc63e21023beefdde700a6bc02036335b4df141c8b" "c67bb05a971f5ac2745fd683797dde302d1e26c2287948bc6ab2b55945c591b8ba3ff" "a237f5d9164d30a4f10145a61f788e639b1480731e2aead30500bf8462872102449fb" - "5237efe8f647d32e8b64f06c22d1d40368eaca2a71ffc6a13ecc8bce680f43f437a2d" - "8910aa81ff6c5619dd7b27a1e4b794841e3ab60a3878cf00cff8c0135dc85e451e179" - "34b252b51b44db5a8761d215565cc9533cdecfda0870ef079d1e26c2287948bc6ab2b" + "5237efe8f647d32e8b64f06c22d1d40368eaca2a71ffc6a13ecc8bce680a23cc05a55" + "dd64d6030f201dac05518e410aabe1f1d1065355b03c1f6b974793a783ee4ddc4a41e" + "df0d55e5ed5fd47f0dd38333fecfeddaf6488c5c98a28b316d1e26c2287948bc6ab2b" "55945c591b8ba3ffa237f5d9164d30a4f10145a61f788e639b1480731e2aead30500b" "f8462872102449fb5237efe8f647d32e8b64f06c22d1d40368eaca2a71ffc6a13ecc8" - "bce680f43f437a2d8910aa81ff6c5619dd7b27a1e4b794841e3ab60a3878cf00cff8c" - "0135dc85e451e17934b252b51b44db5a8761d215565cc9533cdecfda0870ef079", + "bce680a23cc05a55dd64d6030f201dac05518e410aabe1f1d1065355b03c1f6b97479" + "3a783ee4ddc4a41edf0d55e5ed5fd47f0dd38333fecfeddaf6488c5c98a28b316", ProofId::fromHex("a7cd6e76b5766cf4fc2251da4a01668682a1786d4b76539e04d7" "f79cebeb5983"), 3280755132, ProofValidationResult::DUPLICATE_STAKE}, @@ -183,18 +183,18 @@ "c964aa6fde575e4ce8404581c7be874e21023beefdde700a6bc02036335b4df141c8b" "c67bb05a971f5ac2745fd683797dde30305d427b706705a5d4b6a368a231d6db62aba" "cf8c29bc32b61e7f65a0a6976aa8b86b687bc0260e821e4f0200b9d3bf6d2102449fb" - "5237efe8f647d32e8b64f06c22d1d40368eaca2a71ffc6a13ecc8bce68052365271b6" - "c71189f5cd7e3b694b77b579080f0b35bae567b96590ab6aa3019b018ff9f061f52f1" - "426bdb195d4b6d4dff5114cee90e33dabf0c588ebadf7774418f54247f6390791706a" + "5237efe8f647d32e8b64f06c22d1d40368eaca2a71ffc6a13ecc8bce680ad55a338f8" + "cf206a73e29acbdb98930132b0876ed9cea780b483e35d3edce9ecd9d8f5c11d54e97" + "59d91f460fd617a7900a818127170d0c050b5dfbe5cc8d44418f54247f6390791706a" "f36fac782302479898b5273f9e51a92cb1fb5af43deeb6c8c269403d30ffcb3803001" "34398c42103e49f9df52de2dea81cf7838b82521b69f2ea360f1c4eed9e6c89b7d0f9" - "e645efa08e97ea0c60e1f0a064fbf08989c084707082727e85dcb9f79bb503f76ee6c" - "8dad42a07ef15c89b3750a5631d604b21fafff0f4de354ade95c2f28160ae549af0d4" + "e645ef99507bd28c0b2961eacb709334e08eb8938e3ea8fab7f249eac8c7df5fdd4c0" + "c95942e44d1e94aba8e53a0abf69c9b188499cbfe13a01a9bea631f88c8d8afd4f0d4" "ce48c4ca9d0714b1fa51920270f8575e0af610f07b4e602a018ecdbb649b64fff614c" "0026e9fc8e0030092533d422103aac52f4cfca700e7e9824298e0184755112e32f359" - "c832f5f6ad2ef62a2c024af812d6d7f2ecc6223a774e19bce1fb20d94d6b01ea69363" - "8f55c74fdaa5358fa9239d03e4caf3d817e8f748ccad55a27b9d365db06ad5a0b779a" - "c385f3dc8710", + "c832f5f6ad2ef62a2c024a4b784fc0ce126136d43cf8e445d25cb49cac942385d8194" + "613f2207e324ecf5ff8c4fff85b7959dfcdd3fdb19c75ed0097acb95553308073a46e" + "a51ae02a5a5f", ProofId::fromHex("39488854a79a87a37a5042f3934983d116337f0a38cfa0c78712" "26ba8edf6a15"), 2648393347, ProofValidationResult::NONE}, diff --git a/test/functional/abc_rpc_addavalanchenode.py b/test/functional/abc_rpc_addavalanchenode.py --- a/test/functional/abc_rpc_addavalanchenode.py +++ b/test/functional/abc_rpc_addavalanchenode.py @@ -166,8 +166,8 @@ "7b9831c4fcd7c6a0bb9a58e0e0f53d5cbc01683ef49024cf25bb55775b327f5e68" "c79da3a7824dc03df5623c96f4a60158f90000000000f902950000000095010000" "210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d" - "3f612834ef0e2545d6359e9f34967c2bb69cb88fe246fed716d998f3f62eba1ef6" - "6a547606a7ac14c1b5697f4acc20853b3f99954f4f7b6e9bf8a085616d3adfc7" + "3f34cd364868e03e29c86940923c2f31811679adaf546405bd8b06eb96863d4c1b" + "4cbd702396462aebbf2aafe30c50ea8acb108fb5095f61de620159b5264a5697" ) assert node.addavalanchenode(nodeid, hardcoded_pubkey, hardcoded_proof)