Line data Source code
1 : // Copyright (c) 2017-2021 The PIVX Core developers 2 : // Distributed under the MIT software license, see the accompanying 3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : 5 : #include "blocksignature.h" 6 : 7 : #include "script/standard.h" 8 : #include "zpiv/zpivmodule.h" 9 : 10 1937 : static bool GetKeyIDFromUTXO(const CTxOut& utxo, CKeyID& keyIDRet) 11 : { 12 3874 : std::vector<valtype> vSolutions; 13 1937 : txnouttype whichType; 14 2006 : if (utxo.scriptPubKey.empty() || !Solver(utxo.scriptPubKey, whichType, vSolutions)) 15 0 : return false; 16 1937 : if (whichType == TX_PUBKEY) { 17 68 : keyIDRet = CPubKey(vSolutions[0]).GetID(); 18 68 : return true; 19 : } 20 1869 : if (whichType == TX_PUBKEYHASH || whichType == TX_COLDSTAKE) { 21 1869 : keyIDRet = CKeyID(uint160(vSolutions[0])); 22 1869 : return true; 23 : } 24 0 : if (whichType == TX_EXCHANGEADDR) { 25 0 : keyIDRet = CExchangeKeyID(uint160(vSolutions[0])); 26 0 : return true; 27 : } 28 : return false; 29 : } 30 : 31 1977 : bool SignBlockWithKey(CBlock& block, const CKey& key) 32 : { 33 1977 : if (!key.Sign(block.GetHash(), block.vchBlockSig)) 34 0 : return error("%s: failed to sign block hash with key", __func__); 35 : 36 : return true; 37 : } 38 : 39 1937 : bool SignBlock(CBlock& block, const CKeyStore& keystore) 40 : { 41 1937 : CKeyID keyID; 42 1937 : if (!GetKeyIDFromUTXO(block.vtx[1]->vout[1], keyID)) { 43 0 : return error("%s: failed to find key for PoS", __func__); 44 : } 45 : 46 3874 : CKey key; 47 1937 : if (!keystore.GetKey(keyID, key)) 48 0 : return error("%s: failed to get key from keystore", __func__); 49 : 50 1937 : return SignBlockWithKey(block, key); 51 : } 52 : 53 42856 : bool CheckBlockSignature(const CBlock& block) 54 : { 55 42856 : if (block.IsProofOfWork()) 56 36061 : return block.vchBlockSig.empty(); 57 : 58 6795 : if (block.vchBlockSig.empty()) 59 0 : return error("%s: vchBlockSig is empty!", __func__); 60 : 61 : /** Each block is signed by the private key of the input that is staked. This can be either zPIV or normal UTXO 62 : * zPIV: Each zPIV has a keypair associated with it. The serial number is a hash of the public key. 63 : * UTXO: The public key that signs must match the public key associated with the first utxo of the coinstake tx. 64 : */ 65 6795 : CPubKey pubkey; 66 6795 : bool fzPIVStake = block.vtx[1]->vin[0].IsZerocoinSpend(); 67 6795 : if (fzPIVStake) { 68 0 : libzerocoin::CoinSpend spend = ZPIVModule::TxInToZerocoinSpend(block.vtx[1]->vin[0]); 69 0 : pubkey = spend.getPubKey(); 70 : } else { 71 6795 : txnouttype whichType; 72 13580 : std::vector<valtype> vSolutions; 73 6795 : const CTxOut& txout = block.vtx[1]->vout[1]; 74 6795 : if (!Solver(txout.scriptPubKey, whichType, vSolutions)) 75 10 : return false; 76 : 77 6795 : if (whichType == TX_PUBKEY) { 78 88 : valtype& vchPubKey = vSolutions[0]; 79 88 : pubkey = CPubKey(vchPubKey); 80 6707 : } else if (whichType == TX_PUBKEYHASH) { 81 6701 : const CTxIn& txin = block.vtx[1]->vin[0]; 82 : // Check if the scriptSig is for a p2pk or a p2pkh 83 13402 : if (txin.scriptSig.size() == 73) { // Sig size + DER signature size. 84 : // If the input is for a p2pk and the output is a p2pkh. 85 : // We don't have the pubkey to verify the block sig anywhere in this block. 86 : // p2pk scriptsig only contains the signature and p2pkh scriptpubkey only contain the hash. 87 : return false; 88 : } else { 89 13382 : unsigned int start = 1 + (unsigned int) *txin.scriptSig.begin(); // skip sig 90 6691 : if (start >= txin.scriptSig.size() - 1) return false; 91 13382 : pubkey = CPubKey(txin.scriptSig.begin()+start+1, txin.scriptSig.end()); 92 : } 93 6 : } else if (whichType == TX_COLDSTAKE) { 94 : // pick the public key from the P2CS input 95 6 : const CTxIn& txin = block.vtx[1]->vin[0]; 96 12 : unsigned int start = 1 + (unsigned int) *txin.scriptSig.begin(); // skip sig 97 12 : if (start >= txin.scriptSig.size() - 1) return false; 98 6 : start += 1 + (int) *(txin.scriptSig.begin()+start); // skip flag 99 6 : if (start >= txin.scriptSig.size() - 1) return false; 100 12 : pubkey = CPubKey(txin.scriptSig.begin()+start+1, txin.scriptSig.end()); 101 : } 102 : } 103 : 104 6785 : if (!pubkey.IsValid()) 105 0 : return error("%s: invalid pubkey %s", __func__, HexStr(pubkey)); 106 : 107 6785 : return pubkey.Verify(block.GetHash(), block.vchBlockSig); 108 : }