mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-14 12:43:40 +02:00
Range proofs in witness
This commit is contained in:
parent
5093a5c61c
commit
670e7fb32e
3 changed files with 69 additions and 9 deletions
|
|
@ -90,6 +90,9 @@ public:
|
|||
void FromTx(const CTransaction &tx, int nHeightIn) {
|
||||
fCoinBase = tx.IsCoinBase();
|
||||
vout = tx.vout;
|
||||
for (size_t i = 0; i < vout.size(); i++) {
|
||||
CTxOutWitnessSerializer(vout[i]).SetNull();
|
||||
}
|
||||
nHeight = nHeightIn;
|
||||
nVersion = tx.nVersion;
|
||||
ClearUnspendable();
|
||||
|
|
|
|||
|
|
@ -154,13 +154,9 @@ public:
|
|||
if (ser_action.ForRead())
|
||||
SetToBitcoinAmount(nAmount);
|
||||
} else {
|
||||
// Though the range proof + nonce commitment are essentially witness data,
|
||||
// we dont care too much about the space-savings here. Also, since they're
|
||||
// signed by everything (output data), we don't take a malleability hit for
|
||||
// doing this.
|
||||
// We only serialize the value commitment here.
|
||||
// The ECDH key and range proof are serialized through CTxOutWitnessSerializer.
|
||||
READWRITE(REF(CFlatData(&vchCommitment[0], &vchCommitment[nCommitmentSize])));
|
||||
READWRITE(vchRangeproof);
|
||||
READWRITE(vchNonceCommitment);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -271,6 +267,34 @@ public:
|
|||
std::string ToString() const;
|
||||
};
|
||||
|
||||
class CTxOutWitnessSerializer
|
||||
{
|
||||
CTxOut& ref;
|
||||
|
||||
public:
|
||||
CTxOutWitnessSerializer(CTxOut& ref_) : ref(ref_) {}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
bool IsNull() const {
|
||||
return ref.nValue.vchRangeproof.empty() && ref.nValue.vchNonceCommitment.empty();
|
||||
}
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
if (!(nVersion & SERIALIZE_BITCOIN_BLOCK_OR_TX)) {
|
||||
READWRITE(ref.nValue.vchRangeproof);
|
||||
READWRITE(ref.nValue.vchNonceCommitment);
|
||||
}
|
||||
}
|
||||
|
||||
void SetNull() {
|
||||
std::vector<unsigned char>().swap(ref.nValue.vchRangeproof);
|
||||
std::vector<unsigned char>().swap(ref.nValue.vchNonceCommitment);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CTxInWitness
|
||||
{
|
||||
public:
|
||||
|
|
@ -346,13 +370,17 @@ struct CMutableTransaction;
|
|||
* - std::vector<CTxOut> vout
|
||||
* - if (flags & 1):
|
||||
* - CTxWitness wit;
|
||||
* - if (flags & 2):
|
||||
* - CTxOutWitness witout;
|
||||
* - uint32_t nLockTime
|
||||
*/
|
||||
static const CAmount TX_FEE_BITCOIN_TX_FLAG = -42;
|
||||
template<typename Stream, typename Operation, typename TxType>
|
||||
inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
const bool fAllowWitness = !(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
const bool fIsBitcoinTx = (nVersion & SERIALIZE_BITCOIN_BLOCK_OR_TX);
|
||||
READWRITE(*const_cast<int32_t*>(&tx.nVersion));
|
||||
if ((ser_action.ForRead() || (!ser_action.ForRead() && tx.nTxFee != TX_FEE_BITCOIN_TX_FLAG)) && !(nVersion & SERIALIZE_BITCOIN_BLOCK_OR_TX))
|
||||
if ((ser_action.ForRead() || (!ser_action.ForRead() && tx.nTxFee != TX_FEE_BITCOIN_TX_FLAG)) && !fIsBitcoinTx)
|
||||
READWRITE(*const_cast<CAmount*>(&tx.nTxFee));
|
||||
else if (ser_action.ForRead())
|
||||
const_cast<CAmount&>(tx.nTxFee) = TX_FEE_BITCOIN_TX_FLAG;
|
||||
|
|
@ -380,6 +408,21 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in
|
|||
const_cast<CTxWitness*>(&tx.wit)->vtxinwit.resize(tx.vin.size());
|
||||
READWRITE(tx.wit);
|
||||
}
|
||||
if ((flags & 2) && fAllowWitness && !fIsBitcoinTx) {
|
||||
/* The witness output flag is present, and we support witnesses. */
|
||||
flags ^= 2;
|
||||
bool fHadOutputWitness = false;
|
||||
for (size_t i = 0; i < tx.vout.size(); i++) {
|
||||
CTxOutWitnessSerializer witser(REF(tx.vout[i]));
|
||||
READWRITE(witser);
|
||||
if (!witser.IsNull()) {
|
||||
fHadOutputWitness = true;
|
||||
}
|
||||
}
|
||||
if (!fHadOutputWitness) {
|
||||
throw std::ios_base::failure("Superfluous output witness record");
|
||||
}
|
||||
}
|
||||
if (flags) {
|
||||
/* Unknown flag in the serialization */
|
||||
throw std::ios_base::failure("Unknown transaction optional data");
|
||||
|
|
@ -392,6 +435,14 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in
|
|||
if (!tx.wit.IsNull()) {
|
||||
flags |= 1;
|
||||
}
|
||||
if (!fIsBitcoinTx) {
|
||||
for (size_t i = 0; i < tx.vout.size(); i++) {
|
||||
if (!CTxOutWitnessSerializer(*const_cast<CTxOut*>(&tx.vout[i])).IsNull()) {
|
||||
flags |= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags) {
|
||||
/* Use extended format in case witnesses are to be serialized. */
|
||||
|
|
@ -405,6 +456,12 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in
|
|||
const_cast<CTxWitness*>(&tx.wit)->vtxinwit.resize(tx.vin.size());
|
||||
READWRITE(tx.wit);
|
||||
}
|
||||
if (flags & 2) {
|
||||
for (size_t i = 0; i < tx.vout.size(); i++) {
|
||||
CTxOutWitnessSerializer witser(*const_cast<CTxOut*>(&tx.vout[i]));
|
||||
READWRITE(witser);
|
||||
}
|
||||
}
|
||||
}
|
||||
READWRITE(*const_cast<uint32_t*>(&tx.nLockTime));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,9 +71,9 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams)
|
|||
BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), runtime_error);
|
||||
BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), runtime_error);
|
||||
string rawtx = "01000000000000000000000000000002000000000000000000000000000000000000000000000000000000000005f5e10000210336cf214cb1633268d90ef794165de68911661210cb82e61276639b10911e71361976a914261324748d65eaf0fa3e22b1bd79f2f487c9d98188ac00000000000000000000000000000000000000000000000000000000000bebc200002102248846a76f455da4b3d6ca78a021aabcca7e22e9abd5c9813fb27155dd2739871976a91457a463ab039b40e9457abaff84a9bdd39c9caf0088ac69000000";
|
||||
string rawtx = "0100000000000000000000000132313029282726252423222120191817161514131211100908070605040302010000000000ffffffff010000000000000000000000000000000000000000000000000000000000000000000069000000";
|
||||
BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx));
|
||||
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 208);
|
||||
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 93);
|
||||
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1);
|
||||
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 105);
|
||||
BOOST_CHECK_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx+" extra"), runtime_error);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue