Skip to content

Commit

Permalink
Extracted proof verification from applicability to state checks
Browse files Browse the repository at this point in the history
  • Loading branch information
abi87 committed Apr 7, 2021
1 parent ab14627 commit c9ad416
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 64 deletions.
85 changes: 61 additions & 24 deletions src/coins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1075,8 +1075,10 @@ bool CCoinsViewCache::RevertTxOutputs(const CTransaction& tx, int nHeight)
#ifdef BITCOIN_TX
int CCoinsViewCache::GetHeight() const {return -1;}
bool CCoinsViewCache::CheckEndEpochBlockHash(const CSidechain& info, int epochNumber, const uint256& endEpochBlockHash) const {return true;}
bool CCoinsViewCache::IsCertApplicableToState(const CScCertificate& cert, CScProofVerifier& scVerifier) const {return true;}
bool CCoinsViewCache::IsScTxApplicableToState(const CTransaction& tx, CScProofVerifier& scVerifier) const { return true;}
bool CCoinsViewCache::IsCertApplicableToStateWithoutProof(const CScCertificate& cert) const {return true;}
bool CCoinsViewCache::CheckCertificateProof(const CScCertificate& cert, CScProofVerifier& scVerifier) const {return true;}
bool CCoinsViewCache::IsScTxApplicableToStateWithoutProof(const CTransaction& tx) const { return true;}
bool CCoinsViewCache::CheckScTxProof(const CTransaction& scTx, CScProofVerifier& scVerifier) const { return true;}
#else

int CCoinsViewCache::GetHeight() const
Expand Down Expand Up @@ -1125,7 +1127,7 @@ bool CCoinsViewCache::CheckCertTiming(const uint256& scId, int certEpoch) const
return true;
}

bool CCoinsViewCache::IsCertApplicableToState(const CScCertificate& cert, CScProofVerifier& scVerifier) const
bool CCoinsViewCache::IsCertApplicableToStateWithoutProof(const CScCertificate& cert) const
{
const uint256& certHash = cert.GetHash();

Expand Down Expand Up @@ -1154,12 +1156,12 @@ bool CCoinsViewCache::IsCertApplicableToState(const CScCertificate& cert, CScPro

if (!CheckCertTiming(cert.GetScId(), cert.epochNumber))
{
return false;
return error("%s():%d - ERROR: cert %s timing is not valid\n", __func__, __LINE__, certHash.ToString());
}

if (!CheckQuality(cert))
{
return error("%s():%d - ERROR Dropping cert %s : invalid quality\n", __func__, __LINE__, certHash.ToString());
return error("%s():%d - ERROR: cert %s with invalid quality %d\n", __func__, __LINE__, certHash.ToString(), cert.quality);
}

CAmount bwtTotalAmount = cert.GetValueOfBackwardTransfers();
Expand All @@ -1180,6 +1182,23 @@ bool CCoinsViewCache::IsCertApplicableToState(const CScCertificate& cert, CScPro
LogPrint("sc", "%s():%d - ok, balance in scId[%s]: balance[%s], cert amount[%s]\n",
__func__, __LINE__, cert.GetScId().ToString(), FormatMoney(scBalance), FormatMoney(bwtTotalAmount) );

return true;
}

bool CCoinsViewCache::CheckCertificateProof(const CScCertificate& cert, CScProofVerifier& scVerifier) const
{
const uint256& certHash = cert.GetHash();

LogPrint("cert", "%s():%d - called: cert[%s], scId[%s]\n",
__func__, __LINE__, certHash.ToString(), cert.GetScId().ToString());

CSidechain sidechain;
if (!GetSidechain(cert.GetScId(), sidechain))
{
return error("%s():%d - ERROR: cert[%s] refers to scId[%s] not yet created\n",
__func__, __LINE__, certHash.ToString(), cert.GetScId().ToString());
}

// Retrieve current and previous end epoch block info for certificate proof verification
int curr_end_epoch_block_height = sidechain.GetEndHeightForEpoch(cert.epochNumber);
int prev_end_epoch_block_height = curr_end_epoch_block_height - sidechain.creationData.withdrawalEpochLength;
Expand All @@ -1194,12 +1213,13 @@ bool CCoinsViewCache::IsCertApplicableToState(const CScCertificate& cert, CScPro
const CFieldElement& scCumTreeHash_end = curr_end_epoch_block_index->scCumTreeHash;

// TODO Remove prev_end_epoch_block_hash after changing of verification circuit.
uint256 prev_end_epoch_block_hash = prev_end_epoch_block_index->GetBlockHash();
const uint256& prev_end_epoch_block_hash = prev_end_epoch_block_index->GetBlockHash();

// Verify certificate proof
CFieldElement constant{};
if (sidechain.creationData.constant.is_initialized())
constant = sidechain.creationData.constant.get();

if (!scVerifier.verifyCScCertificate(constant, sidechain.creationData.wCertVk, prev_end_epoch_block_hash, cert))
{
return error("%s():%d - ERROR: certificate[%s] cannot be accepted for sidechain [%s]: proof verification failed\n",
Expand Down Expand Up @@ -1248,7 +1268,7 @@ bool CCoinsViewCache::CheckScTxTiming(const uint256& scId) const
return true;
}

bool CCoinsViewCache::IsScTxApplicableToState(const CTransaction& tx, CScProofVerifier& scVerifier) const
bool CCoinsViewCache::IsScTxApplicableToStateWithoutProof(const CTransaction& tx) const
{
if (tx.IsCoinBase())
return true;
Expand Down Expand Up @@ -1305,21 +1325,6 @@ bool CCoinsViewCache::IsScTxApplicableToState(const CTransaction& tx, CScProofVe
{
return error("%s():%d - ERROR: mbtr not supported\n", __func__, __LINE__);
}

CFieldElement certDataHash = this->GetActiveCertDataHash(mbtr.scId);
// //TODO: Unlock when we'll handle recovery of fwt of last epoch
// if (certDataHash.IsNull())
// return error("%s():%d - ERROR: Tx[%s] mbtr request [%s] has missing active cert data hash for required scId[%s]\n",
// __func__, __LINE__, tx.ToString(), mbtr.ToString(), mbtr.scId.ToString());

// Verify mainchain bwt request proof
if (!scVerifier.verifyCBwtRequest(mbtr.scId, mbtr.scRequestData,
mbtr.mcDestinationAddress, mbtr.scFee, mbtr.scProof, wMbtrVk, certDataHash))
return error("%s():%d - ERROR: mbtr for scId [%s], tx[%s], pos[%d] cannot be accepted : proof verification failed\n",
__func__, __LINE__, mbtr.scId.ToString(), tx.GetHash().ToString(), idx);

LogPrint("sc", "%s():%d - OK: tx[%s] contains bwt transfer request for scId[%s]\n",
__func__, __LINE__, txHash.ToString(), scId.ToString());
}

// Check CSW inputs
Expand Down Expand Up @@ -1361,19 +1366,51 @@ bool CCoinsViewCache::IsScTxApplicableToState(const CTransaction& tx, CScProofVe
return error("%s():%d - ERROR: Tx[%s] CSW input [%s] nullifier had been already used\n",
__func__, __LINE__, tx.ToString(), csw.ToString());
}
}

return true;
}

bool CCoinsViewCache::CheckScTxProof(const CTransaction& scTx, CScProofVerifier& scVerifier) const
{
// verify mbtr
for(size_t idx = 0; idx < scTx.GetVBwtRequestOut().size(); ++idx)
{
const CBwtRequestOut& mbtr = scTx.GetVBwtRequestOut().at(idx);

boost::optional<CScVKey> wMbtrVk = this->AccessSidechain(mbtr.scId)->creationData.wMbtrVk;
CFieldElement certDataHash = this->GetActiveCertDataHash(mbtr.scId);
// //TODO: Unlock when we'll handle recovery of fwt of last epoch
// if (certDataHash.IsNull())
// return error("%s():%d - ERROR: Tx[%s] mbtr request [%s] has missing active cert data hash for required scId[%s]\n",
// __func__, __LINE__, tx.ToString(), mbtr.ToString(), mbtr.scId.ToString());

// Verify mainchain bwt request proof
if (!scVerifier.verifyCBwtRequest(mbtr.scId, mbtr.scRequestData,
mbtr.mcDestinationAddress, mbtr.scFee, mbtr.scProof, wMbtrVk, certDataHash))
return error("%s():%d - ERROR: mbtr for scId [%s], tx[%s], pos[%d] cannot be accepted : proof verification failed\n",
__func__, __LINE__, mbtr.scId.ToString(), scTx.GetHash().ToString(), idx);

LogPrint("sc", "%s():%d - OK: tx[%s] contains bwt transfer request for scId[%s]\n",
__func__, __LINE__, scTx.GetHash().ToString(), mbtr.scId.ToString());
}

// verify csws
for(const CTxCeasedSidechainWithdrawalInput& csw: scTx.GetVcswCcIn())
{
CFieldElement certDataHash = this->GetActiveCertDataHash(csw.scId);
boost::optional<CScVKey> wCeasedVk = this->AccessSidechain(csw.scId)->creationData.wCeasedVk;

// //TODO: Unlock when we'll handle recovery of fwt of last epoch
// if (certDataHash.IsNull())
// return error("%s():%d - ERROR: Tx[%s] CSW input [%s] has missing active cert data hash for required scId[%s]\n",
// __func__, __LINE__, tx.ToString(), csw.ToString(), csw.scId.ToString());

// Verify CSW proof
if (!scVerifier.verifyCTxCeasedSidechainWithdrawalInput(certDataHash, sidechain.creationData.wCeasedVk.get(), csw))
if (!scVerifier.verifyCTxCeasedSidechainWithdrawalInput(certDataHash, wCeasedVk.get(), csw))
{
return error("%s():%d - ERROR: Tx[%s] CSW input [%s] cannot be accepted: proof verification failed\n",
__func__, __LINE__, tx.ToString(), csw.ToString());
__func__, __LINE__, scTx.GetHash().ToString(), csw.ToString());
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/coins.h
Original file line number Diff line number Diff line change
Expand Up @@ -672,14 +672,16 @@ class CCoinsViewCache : public CCoinsViewBacked
bool GetSidechain(const uint256 & scId, CSidechain& targetSidechain) const override;
void GetScIds(std::set<uint256>& scIdsList) const override;

bool IsScTxApplicableToState(const CTransaction& tx, CScProofVerifier& scVerifier) const;
bool IsScTxApplicableToStateWithoutProof(const CTransaction& tx) const;
bool CheckScTxProof(const CTransaction& scTx, CScProofVerifier& scVerifier) const;
bool CheckScTxTiming(const uint256& scId) const;
bool UpdateSidechain(const CTransaction& tx, const CBlock&, int nHeight);
bool RevertTxOutputs(const CTransaction& tx, int nHeight);
int getScCoinsMaturity();

//CERTIFICATES RELATED PUBLIC MEMBERS
bool IsCertApplicableToState(const CScCertificate& cert, CScProofVerifier& scVerifier) const;
bool IsCertApplicableToStateWithoutProof(const CScCertificate& cert) const;
bool CheckCertificateProof(const CScCertificate& cert, CScProofVerifier& scVerifier) const;
bool CheckEndEpochBlockHash(const CSidechain& sidechain, int epochNumber, const uint256& epochBlockHash) const;
bool CheckCertTiming(const uint256& scId, int certEpoch) const;
bool UpdateSidechain(const CScCertificate& cert, CBlockUndo& blockUndo);
Expand Down
42 changes: 20 additions & 22 deletions src/gtest/test_sidechain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ class SidechainsTestSuite: public ::testing::Test {
public:
SidechainsTestSuite():
fakeChainStateDb(nullptr)
, sidechainsView(nullptr)
, dummyScVerifier{CScProofVerifier::Verification::Loose} {};
, sidechainsView(nullptr) {};

~SidechainsTestSuite() = default;

Expand All @@ -126,7 +125,6 @@ class SidechainsTestSuite: public ::testing::Test {
CNakedCCoinsViewCache *sidechainsView;

//Helpers
CScProofVerifier dummyScVerifier;
CBlockUndo createBlockUndoWith(const uint256 & scId, int height, CAmount amount, uint256 lastCertHash = uint256());
void storeSidechainWithCurrentHeight(const uint256& scId, const CSidechain& sidechain, int chainActiveHeight);
};
Expand Down Expand Up @@ -432,7 +430,7 @@ TEST(SidechainsAmounts, ScFeesLargerThanInputAreRejected)
EXPECT_FALSE(CTransaction(mutTx).CheckFeeAmount(totalVinAmount, dummyState));
}
///////////////////////////////////////////////////////////////////////////////
/////////////////////////// IsScTxApplicableToState ///////////////////////////
///////////////////// IsScTxApplicableToStateWithoutProof /////////////////////
///////////////////////////////////////////////////////////////////////////////

TEST_F(SidechainsTestSuite, ScCreationIsApplicableToStateIfScDoesntNotExistYet) {
Expand All @@ -441,7 +439,7 @@ TEST_F(SidechainsTestSuite, ScCreationIsApplicableToStateIfScDoesntNotExistYet)
ASSERT_FALSE(sidechainsView->HaveSidechain(scId));

//test
bool res = sidechainsView->IsScTxApplicableToState(aTransaction, dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(aTransaction);

//checks
EXPECT_TRUE(res);
Expand All @@ -461,7 +459,7 @@ TEST_F(SidechainsTestSuite, ScCreationIsNotApplicableToStateIfScIsAlreadyUnconfi
ASSERT_TRUE(sidechainsView->GetSidechainState(scId) == CSidechain::State::UNCONFIRMED);

//test
bool res = sidechainsView->IsScTxApplicableToState(scCreationTx, dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(scCreationTx);

//checks
EXPECT_FALSE(res);
Expand All @@ -481,7 +479,7 @@ TEST_F(SidechainsTestSuite, ScCreationIsNotApplicableToStateIfScIsAlreadyAlive)
ASSERT_TRUE(sidechainsView->GetSidechainState(scId) == CSidechain::State::ALIVE);

//test
bool res = sidechainsView->IsScTxApplicableToState(aTransaction, dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(aTransaction);

//checks
EXPECT_FALSE(res);
Expand All @@ -501,7 +499,7 @@ TEST_F(SidechainsTestSuite, ScCreationIsNotApplicableToStateIfScIsAlreadyCeased)
ASSERT_TRUE(sidechainsView->GetSidechainState(scId) == CSidechain::State::CEASED);

//test
bool res = sidechainsView->IsScTxApplicableToState(aTransaction, dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(aTransaction);

//checks
EXPECT_FALSE(res);
Expand All @@ -515,7 +513,7 @@ TEST_F(SidechainsTestSuite, ForwardTransferToUnknownSCsIsApplicableToState) {
CTransaction aTransaction = txCreationUtils::createFwdTransferTxWith(scId, CAmount(5));

//test
bool res = sidechainsView->IsScTxApplicableToState(aTransaction, dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(aTransaction);

//checks
EXPECT_FALSE(res);
Expand All @@ -536,7 +534,7 @@ TEST_F(SidechainsTestSuite, ForwardTransferToUnconfirmedSCsIsApplicableToState)

//test
CTransaction fwdTx = txCreationUtils::createFwdTransferTxWith(scId, CAmount(5));
bool res = sidechainsView->IsScTxApplicableToState(fwdTx, dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(fwdTx);

//checks
EXPECT_TRUE(res);
Expand All @@ -556,7 +554,7 @@ TEST_F(SidechainsTestSuite, ForwardTransferToAliveSCsIsApplicableToState) {
CTransaction aTransaction = txCreationUtils::createFwdTransferTxWith(scId, CAmount(5));

//test
bool res = sidechainsView->IsScTxApplicableToState(aTransaction, dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(aTransaction);

//checks
EXPECT_TRUE(res);
Expand All @@ -576,7 +574,7 @@ TEST_F(SidechainsTestSuite, ForwardTransferToCeasedSCsIsNotApplicableToState) {
CTransaction aTransaction = txCreationUtils::createFwdTransferTxWith(scId, CAmount(5));

//test
bool res = sidechainsView->IsScTxApplicableToState(aTransaction, dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(aTransaction);

//checks
EXPECT_FALSE(res);
Expand All @@ -603,7 +601,7 @@ TEST_F(SidechainsTestSuite, McBwtRequestToAliveSidechainWithKeyIsApplicableToSta
mutTx.vmbtr_out.push_back(mcBwtReq);

//test
bool res = sidechainsView->IsScTxApplicableToState(CTransaction(mutTx), dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(CTransaction(mutTx));

//checks
EXPECT_TRUE(res);
Expand Down Expand Up @@ -637,7 +635,7 @@ TEST_F(SidechainsTestSuite, McBwtRequestToUnconfirmedSidechainWithKeyIsApplicabl
mutTx.vmbtr_out.push_back(mcBwtReq);

//test
bool res = sidechainsView->IsScTxApplicableToState(CTransaction(mutTx), dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(CTransaction(mutTx));

//checks
EXPECT_TRUE(res);
Expand All @@ -654,7 +652,7 @@ TEST_F(SidechainsTestSuite, McBwtRequestToUnknownSidechainIsNotApplicableToState
mutTx.vmbtr_out.push_back(mcBwtReq);

//test
bool res = sidechainsView->IsScTxApplicableToState(CTransaction(mutTx), dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(CTransaction(mutTx));

//checks
EXPECT_FALSE(res);
Expand Down Expand Up @@ -685,7 +683,7 @@ TEST_F(SidechainsTestSuite, McBwtRequestToAliveSidechainWithoutKeyIsNotApplicabl
mutTx.vmbtr_out.push_back(mcBwtReq);

//test
bool res = sidechainsView->IsScTxApplicableToState(CTransaction(mutTx), dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(CTransaction(mutTx));

//checks
EXPECT_FALSE(res);
Expand Down Expand Up @@ -722,7 +720,7 @@ TEST_F(SidechainsTestSuite, McBwtRequestToUnconfirmedSidechainWithoutKeyIsNotApp
mutTx.vmbtr_out.push_back(mcBwtReq);

//test
bool res = sidechainsView->IsScTxApplicableToState(CTransaction(mutTx), dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(CTransaction(mutTx));

//checks
EXPECT_FALSE(res);
Expand All @@ -748,7 +746,7 @@ TEST_F(SidechainsTestSuite, McBwtRequestToCeasedSidechainIsNotApplicableToState)
mutTx.vmbtr_out.push_back(mcBwtReq);

//test
bool res = sidechainsView->IsScTxApplicableToState(CTransaction(mutTx), dummyScVerifier);
bool res = sidechainsView->IsScTxApplicableToStateWithoutProof(CTransaction(mutTx));

//checks
EXPECT_FALSE(res);
Expand All @@ -771,7 +769,7 @@ TEST_F(SidechainsTestSuite, CSWsToCeasedSidechainIsAccepted) {
CTxCeasedSidechainWithdrawalInput cswInput = txCreationUtils::CreateCSWInput(scId, "aabb", cswTxCoins);
CTransaction cswTx = txCreationUtils::createCSWTxWith(cswInput);

EXPECT_TRUE(sidechainsView->IsScTxApplicableToState(cswTx, dummyScVerifier));
EXPECT_TRUE(sidechainsView->IsScTxApplicableToStateWithoutProof(cswTx));
}

TEST_F(SidechainsTestSuite, ExcessiveAmountOfCSWsToCeasedSidechainIsRejected) {
Expand All @@ -791,7 +789,7 @@ TEST_F(SidechainsTestSuite, ExcessiveAmountOfCSWsToCeasedSidechainIsRejected) {
CTxCeasedSidechainWithdrawalInput cswInput = txCreationUtils::CreateCSWInput(scId, "aabb", cswTxCoins);
CTransaction cswTx = txCreationUtils::createCSWTxWith(cswInput);

EXPECT_FALSE(sidechainsView->IsScTxApplicableToState(cswTx, dummyScVerifier));
EXPECT_FALSE(sidechainsView->IsScTxApplicableToStateWithoutProof(cswTx));
}

TEST_F(SidechainsTestSuite, CSWsToUnknownSidechainIsRefused) {
Expand All @@ -802,7 +800,7 @@ TEST_F(SidechainsTestSuite, CSWsToUnknownSidechainIsRefused) {
CTxCeasedSidechainWithdrawalInput cswInput = txCreationUtils::CreateCSWInput(unknownScId, "aabb", cswTxCoins);
CTransaction cswTx = txCreationUtils::createCSWTxWith(cswInput);

EXPECT_FALSE(sidechainsView->IsScTxApplicableToState(cswTx, dummyScVerifier));
EXPECT_FALSE(sidechainsView->IsScTxApplicableToStateWithoutProof(cswTx));
}

TEST_F(SidechainsTestSuite, CSWsToActiveSidechainIsRefused) {
Expand All @@ -822,7 +820,7 @@ TEST_F(SidechainsTestSuite, CSWsToActiveSidechainIsRefused) {
CTxCeasedSidechainWithdrawalInput cswInput = txCreationUtils::CreateCSWInput(scId, "aabb", cswTxCoins);
CTransaction cswTx = txCreationUtils::createCSWTxWith(cswInput);

EXPECT_FALSE(sidechainsView->IsScTxApplicableToState(cswTx, dummyScVerifier));
EXPECT_FALSE(sidechainsView->IsScTxApplicableToStateWithoutProof(cswTx));
}
/////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// RevertTxOutputs ///////////////////////////////
Expand Down
Loading

0 comments on commit c9ad416

Please sign in to comment.