Skip to content

Commit f6a0f1f

Browse files
committed
Merge #260: Revamp peg-in transactions
3ff4aab update unit test (Gregory Sanders) 6cc380a don't require claim_script to be witness program for raw claim pegin (Gregory Sanders) da6960d validation variables changed to not assume witness program for pegin (Gregory Sanders) 2940c4e remove tabs from IsValidPegin (Gregory Sanders) b401ff0 change explanation of policy asset seeding in python tutorial (Gregory Sanders) 7dc4f9d remove CNumScript from pegin witness logic (Gregory Sanders) abafbac change rpc test witness_program to claim_script (Gregory Sanders) 851a30b Don't restrict pegin witness to 'witness program' definition (Gregory Sanders) 13c3dad de-dupe calculate_contract code (Gregory Sanders) 6534bd3 Add is_pegin response for raw transaction RPCs (Gregory Sanders) d4d00da basic functional test for peg-in reorgs in sidechain (Gregory Sanders) 4aad513 Add unit tests for peg-in authorization (Gregory Sanders) be735cf re-add pegging python test (Gregory Sanders) 3ba146d update assets tutorial to support new peg-in format (Gregory Sanders) 6e8e6b2 add wallet support for pegging functionality (Gregory Sanders) 7633839 add raw rpc support for peg-in functionality (Gregory Sanders) ff5e9cd mempool and policy support for peg-in inputs (Gregory Sanders) 6bad4e9 add blocks that have pegins rejected to the reconsider queue (Gregory Sanders) 0b9c5eb begin consensus support for peg-ins (Gregory Sanders) 34d7cd0 add pegin witness validation and extraction helper functions (Gregory Sanders) 16973cd add pegin_witness to witness inputs (Gregory Sanders) 36b3ab1 add serialization flag support for peg-in inputs (Gregory Sanders) 9a9ac25 genesis block has actual fee issuance in regtest (Gregory Sanders) 65ed777 remove legacy peg-in/withdrawlocks (Gregory Sanders)
2 parents b2bbc67 + 3ff4aab commit f6a0f1f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1179
-1725
lines changed

contrib/assets_tutorial/assets_tutorial.py

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ def sync_all(e1, e2):
4646
time.sleep(1)
4747
return
4848

49-
5049
## Preparations
5150

5251
# Make data directories for each daemon
@@ -91,20 +90,19 @@ def sync_all(e1, e2):
9190
# Alternatively, you can set validatepegin=0 in their configs and not
9291
# run the bitcoin node, but it is necessary for fully validating the two way peg.
9392

94-
# At beginning "immature balance" holds all funds until genesis is mature
95-
# Regtest chain starts with 21M elements coins as OP_TRUE which the wallet
96-
# understands. This is useful for testing basic functionality.
97-
# In Elements there is no block subsidy. All 21M output value in a mainnet
98-
# pegged sidechain are locked for pegging.
93+
# Regtest chain starts with 21M bitcoins as OP_TRUE which the wallet
94+
# understands. This is useful for testing basic functionality and for
95+
# blockchains that have no pegging functionality. A fee currency is required
96+
# for anti-DoS purposes as well as asset issuance, which consumes inputs for entropy.
97+
# In Elements there is no block subsidy. In a production sidechain it can
98+
# be configured to start with no outputs, necessitating peg-in functionality
99+
# for asset issuance.
99100
e1.getwalletinfo()
100101

101102
# In regtest mining "target" is OP_TRUE since we have not set `-signblockscript` argument
102103
# Generate simply works.
103104
e1.generate(101)
104105
sync_all(e1, e2)
105-
# Now we have 21M OP_TRUE value in each Elements wallet.
106-
e1.getwalletinfo()
107-
e2.getwalletinfo()
108106

109107
######## WALLET ###########
110108

@@ -419,12 +417,6 @@ def sync_all(e1, e2):
419417
bitcoin.generate(101)
420418
sync_all(e1, e2)
421419

422-
# We have to lock up some of the funds first. Regtest(what we're running) has all funds as OP_TRUE
423-
# but this is not the case in testnet/production. Doesn't matter where we send it
424-
# inside Bitcoin, this is just a hack to lock some funds up.
425-
# We can immediately grab this output from the mempool on subsequent steps
426-
e1.sendtomainchain(bitcoin.getnewaddress(), 50)
427-
428420
# Now we can actually start pegging in. Examine the pegin address fields
429421
e1.getpeginaddress()
430422
# Changes each time as it's a new sidechain address as well as new "tweak" for the watchmen keys
@@ -448,7 +440,7 @@ def sync_all(e1, e2):
448440
raw = bitcoin.getrawtransaction(txid)
449441

450442
# Attempt claim!
451-
claimtxid = e1.claimpegin(raw, proof, addrs["sidechain_address"])
443+
claimtxid = e1.claimpegin(raw, proof, addrs["claim_script"])
452444
sync_all(e1, e2)
453445

454446
# Other node should accept to mempool and mine

contrib/assets_tutorial/assets_tutorial.sh

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,11 @@ e2-dae
3939
# run the bitcoin node, but it is necessary for the two way peg parts of
4040
# this tutorial.
4141

42-
# Prime the chain, see "immature balance" holds all funds until genesis is mature
43-
e1-cli getwalletinfo
44-
45-
# Mining for now is OP_TRUE
46-
e1-cli generate 101
47-
48-
# Now we have 21M OP_TRUE value
42+
# We have 21M OP_TRUE value in each wallet
43+
# This is useful for testing and non-sidechain applications of Elements
4944
e1-cli getwalletinfo
5045
e2-cli getwalletinfo
5146

52-
# Primed and ready
53-
5447
######## WALLET ###########
5548

5649

@@ -311,19 +304,11 @@ e2-dae $FEDPEGARG
311304
e1-cli generate 101
312305
b-cli generate 101
313306

314-
# We have to lock up some of the funds first. Regtest(what we're running) has all funds as OP_TRUE
315-
# but this is not the case in testnet/production. Doesn't matter where we send it
316-
# inside Bitcoin, this is just a hack to lock some funds up.
317-
e1-cli sendtomainchain $(b-cli getnewaddress) 50
318-
319-
# Mature the pegout
320-
e1-cli generate 101
321-
322307
# Now we can actually start pegging in. Examine the pegin address fields
323308
e1-cli getpeginaddress
324309
# Changes each time as it's a new sidechain address as well as new "tweak" for the watchmen keys
325310
# mainchain_address : where you send your bitcoin from Bitcoin network
326-
# sidechain_address : where the bitcoin will end up on the sidechain after pegging in
311+
# claim_script: what script will have to be satisfied to spent the peg-in input
327312

328313
# Each call of this takes the pubkeys defined in the config file, adds a random number to them
329314
# that is essetially the hash of the sidechain_address and other information,
@@ -335,7 +320,7 @@ e1-cli getpeginaddress
335320
ADDRS=$(e1-cli getpeginaddress)
336321

337322
MAINCHAIN=$(echo $ADDRS | python3 -c "import sys, json; print(json.load(sys.stdin)['mainchain_address'])")
338-
SIDECHAIN=$(echo $ADDRS | python3 -c "import sys, json; print(json.load(sys.stdin)['sidechain_address'])")
323+
SIDECHAIN=$(echo $ADDRS | python3 -c "import sys, json; print(json.load(sys.stdin)['claim_script'])")
339324

340325
#Send funds to unique watchmen P2SH address
341326
TXID=$(b-cli sendtoaddress $MAINCHAIN 1)

qa/rpc-tests/confidential_transactions.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ def run_test(self):
222222

223223
print("Assets tests...")
224224

225+
# Bitcoin is the first issuance
226+
assert_equal(self.nodes[0].listissuances()[0]["assetlabel"], "bitcoin")
227+
assert_equal(len(self.nodes[0].listissuances()), 1)
228+
225229
# Unblinded issuance of asset
226230
issued = self.nodes[0].issueasset(1, 1, False)
227231
assert_equal(self.nodes[0].getwalletinfo()["balance"][issued["asset"]], 1)
@@ -351,13 +355,13 @@ def run_test(self):
351355
addr2 = txdet2[len(txdet2)-1]["address"]
352356
addr3 = txdet3[len(txdet3)-1]["address"]
353357

354-
assert_equal(len(self.nodes[0].listissuances()), 5);
358+
assert_equal(len(self.nodes[0].listissuances()), 6);
355359
self.nodes[0].importaddress(addr1)
356360
self.nodes[0].importaddress(addr2)
357361
self.nodes[0].importaddress(addr3)
358362

359363
issuances = self.nodes[0].listissuances()
360-
assert_equal(len(issuances), 8)
364+
assert_equal(len(issuances), 9)
361365

362366
for issue in issuances:
363367
if issue['txid'] == redata1["txid"] and issue['vin'] == redata1["vin"]:

qa/rpc-tests/pegging.py

Lines changed: 47 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,22 @@
1414
print(sys.argv[1])
1515
print(sys.argv[2])
1616

17+
# Sync mempool, make a block, sync blocks
18+
def sync_all(sidechain, sidechain2):
19+
timeout = 20
20+
while len(sidechain.getrawmempool()) != len(sidechain2.getrawmempool()):
21+
time.sleep(1)
22+
timeout -= 1
23+
if timeout == 0:
24+
raise Exception("Peg-in has failed to propagate.")
25+
block = sidechain2.generate(1)
26+
while sidechain.getblockcount() != sidechain2.getblockcount():
27+
time.sleep(1)
28+
timeout -= 1
29+
if timeout == 0:
30+
raise Exception("Blocks are not propagating.")
31+
return block
32+
1733
fedpeg_key="cPxqWyf1HDGpGFH1dnfjz8HbiWxvwG8WXyetbuAiw4thKXUdXLpR"
1834
fedpeg_pubkey="512103dff4923d778550cc13ce0d887d737553b4b58f4e8e886507fc39f5e447b2186451ae"
1935

@@ -88,7 +104,7 @@
88104

89105
try:
90106

91-
# Default is 8, meaning 8+2 confirms for mempool acceptance normally
107+
# Default is 8, meaning 8+2 confirms for wallet acceptance normally
92108
# this will require 10+2.
93109
sidechain_args = " -peginconfirmationdepth=10 "
94110

@@ -116,16 +132,8 @@
116132

117133
addr = bitcoin.getnewaddress()
118134

119-
# Lockup some funds to unlock later
120-
sidechain.sendtomainchain(addr, 50)
121-
# Tests withdrawlock tracking in database
122-
sidechain.generate(1)
123-
# Tests withdrawlock in mempool
124-
sidechain.sendtomainchain(addr, 50)
125-
126135
addrs = sidechain.getpeginaddress()
127136
txid1 = bitcoin.sendtoaddress(addrs["mainchain_address"], 24)
128-
txid2 = bitcoin.sendtoaddress(addrs["mainchain_address"], 24)
129137
# 10+2 confirms required to get into mempool and confirm
130138
bitcoin.generate(11)
131139
time.sleep(2)
@@ -137,59 +145,55 @@
137145
pegtxid = sidechain.claimpegin(raw, proof)
138146
raise Exception("Peg-in should not mature enough yet, need another block.")
139147
except JSONRPCException as e:
140-
assert("Withdraw proof validation failed" in e.error["message"])
148+
assert("Peg-in Bitcoin transaction needs more confirmations to be sent." in e.error["message"])
141149
pass
142150

143151
# Should fail due to non-matching wallet address
144152
try:
145153
pegtxid = sidechain.claimpegin(raw, proof, sidechain.getnewaddress())
146-
raise Exception("Peg-in with non-matching address should fail.")
154+
raise Exception("Peg-in with non-matching claim_script should fail.")
147155
except JSONRPCException as e:
148-
assert("Failed to find output in bitcoinTx to the mainchain_address" in e.error["message"])
156+
assert("Given claim_script does not match the given Bitcoin transaction." in e.error["message"])
149157
pass
150158

151159
# 12 confirms allows in mempool
152160
bitcoin.generate(1)
153-
154-
timeout = 20
155-
# Both should succeed via wallet lookup for address match, and when given
161+
# Should succeed via wallet lookup for address match, and when given
156162
pegtxid1 = sidechain.claimpegin(raw, proof)
157163

158-
proof = bitcoin.gettxoutproof([txid2])
159-
raw = bitcoin.getrawtransaction(txid2)
160-
pegtxid2 = sidechain.claimpegin(raw, proof, addrs["sidechain_address"])
161-
162-
while len(sidechain.getrawmempool()) != len(sidechain2.getrawmempool()):
163-
time.sleep(1)
164-
timeout -= 1
165-
if timeout == 0:
166-
raise Exception("Peg-in has failed to propagate.")
167-
sidechain2.generate(1)
168-
while sidechain.getblockcount() != sidechain2.getblockcount():
169-
time.sleep(1)
170-
timeout -= 1
171-
if timeout == 0:
172-
raise Exception("Blocks are not propagating.")
173-
164+
# Will invalidate the block that confirms this transaction later
165+
blockhash = sync_all(sidechain, sidechain2)
166+
sidechain.generate(5)
174167

175168
tx1 = sidechain.gettransaction(pegtxid1)
176-
tx2 = sidechain.gettransaction(pegtxid2)
177169

178-
if "confirmations" in tx1 and tx1["confirmations"] > 0 and "confirmations" in tx2 and tx2["confirmations"] > 0:
170+
if "confirmations" in tx1 and tx1["confirmations"] == 6:
179171
print("Peg-in is confirmed: Success!")
180172
else:
181173
raise Exception("Peg-in confirmation has failed.")
182174

183-
# Make a few large locks, then do many claims in mempool
184-
n_locks = 10
185-
n_claims = 30
175+
# Look at pegin fields
176+
decoded = sidechain.decoderawtransaction(tx1["hex"])
177+
assert decoded["vin"][0]["is_pegin"] == True
178+
assert len(decoded["vin"][0]["pegin_witness"]) > 0
179+
180+
# Quick reorg checks of pegs
181+
sidechain.invalidateblock(blockhash[0])
182+
if sidechain.gettransaction(pegtxid1)["confirmations"] != 0:
183+
raise Exception("Peg-in didn't unconfirm after invalidateblock call.")
184+
# Re-enters block
185+
sidechain.generate(1)
186+
if sidechain.gettransaction(pegtxid1)["confirmations"] != 1:
187+
raise Exception("Peg-in should have one confirm on side block.")
188+
sidechain.reconsiderblock(blockhash[0])
189+
if sidechain.gettransaction(pegtxid1)["confirmations"] != 6:
190+
raise Exception("Peg-in should be back to 6 confirms.")
191+
192+
# Do many claims in mempool
193+
n_claims = 100
186194

187195
print("Flooding mempool with many small claims")
188196
pegtxs = []
189-
for i in range(n_locks):
190-
# Lockup some funds to unlock later
191-
sidechain.sendtomainchain(addr, 50)
192-
sidechain.generate(1)
193197
sidechain.generate(101)
194198

195199
for i in range(n_claims):
@@ -200,21 +204,16 @@
200204
raw = bitcoin.getrawtransaction(txid)
201205
pegtxs += [sidechain.claimpegin(raw, proof)]
202206

203-
sidechain.generate(1)
207+
sync_all(sidechain, sidechain2)
208+
209+
sidechain2.generate(1)
204210
for pegtxid in pegtxs:
205211
tx = sidechain.gettransaction(pegtxid)
206212
if "confirmations" not in tx or tx["confirmations"] == 0:
207213
raise Exception("Peg-in confirmation has failed.")
208214

209215
print("Success!")
210216

211-
# Testing sidechain info RPC
212-
sideinfo = sidechain.getsidechaininfo()
213-
assert sideinfo["fedpegscript"] == fedpeg_pubkey
214-
assert sideinfo["pegged_asset"] == sidechain.dumpassetlabels()["bitcoin"]
215-
assert sideinfo["min_peg_diff"] == "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
216-
assert sideinfo["parent_blockhash"] == "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
217-
218217
except JSONRPCException as e:
219218
print("Pegging testing failed, aborting:")
220219
print(e.error)

qa/rpc-tests/wallet.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,15 @@ def setup_network(self, split=False):
3030

3131
def run_test (self):
3232

33-
# Check that there's no UTXO on none of the nodes
34-
assert_equal(len(self.nodes[0].listunspent()), 0)
35-
assert_equal(len(self.nodes[1].listunspent()), 0)
36-
assert_equal(len(self.nodes[2].listunspent()), 0)
33+
# Check that there's 100 UTXOs on each of the nodes
34+
assert_equal(len(self.nodes[0].listunspent()), 100)
35+
assert_equal(len(self.nodes[1].listunspent()), 100)
36+
assert_equal(len(self.nodes[2].listunspent()), 100)
3737

38-
print("Mining blocks...")
39-
40-
self.nodes[0].generate(1)
4138
walletinfo = self.nodes[0].getwalletinfo()
42-
assert_equal(walletinfo['immature_balance']["bitcoin"], 21000000)
43-
assert("bitcoin" not in walletinfo['balance'])
39+
assert_equal(walletinfo['balance']["bitcoin"], 21000000)
4440

45-
self.sync_all()
41+
print("Mining blocks...")
4642
self.nodes[1].generate(101)
4743
self.sync_all()
4844

src/Makefile.am

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ libbitcoin_wallet_a_SOURCES = \
239239
wallet/wallet.cpp \
240240
wallet/walletdb.cpp \
241241
policy/rbf.cpp \
242+
primitives/bitcoin/merkleblock.cpp \
243+
primitives/bitcoin/block.cpp \
242244
$(BITCOIN_CORE_H)
243245

244246
# crypto primitives library
@@ -458,7 +460,7 @@ endif
458460

459461
libelementsconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 1:0:0 $(RELDFLAGS)
460462
libelementsconsensus_la_LIBADD = $(LIBSECP256K1)
461-
libelementsconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL -DBITCOIN_SCRIPT_NO_CALLRPC
463+
libelementsconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL
462464
libelementsconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
463465

464466
endif

src/Makefile.test.include

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ BITCOIN_TESTS =\
100100
test/hash_tests.cpp \
101101
test/key_tests.cpp \
102102
test/limitedmap_tests.cpp \
103-
test/lockedutxo_tests.cpp \
104103
test/withdrawspent_tests.cpp \
105104
test/dbwrapper_tests.cpp \
106105
test/main_tests.cpp \
@@ -110,6 +109,7 @@ BITCOIN_TESTS =\
110109
test/multisig_tests.cpp \
111110
test/net_tests.cpp \
112111
test/netbase_tests.cpp \
112+
test/pegin_witness_tests.cpp \
113113
test/pmt_tests.cpp \
114114
test/policyestimator_tests.cpp \
115115
test/pow_tests.cpp \

src/bench/mempool_eviction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
1616
unsigned int nHeight = 1;
1717
bool spendsCoinbase = false;
1818
unsigned int sigOpCost = 4;
19-
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
19+
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
2020
LockPoints lp;
2121
pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
2222
MakeTransactionRef(tx), nFee, nTime, dPriority, nHeight,
23-
0, spendsCoinbase, sigOpCost, lp, setWithdrawsSpent));
23+
0, spendsCoinbase, sigOpCost, lp, setPeginsSpent));
2424
}
2525

2626
// Right now this is only testing eviction performance in an extremely small

src/bench/verify_script.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ static void VerifyScriptBench(benchmark::State& state)
8181
txCredit.vout[0].scriptPubKey,
8282
&txSpend.wit.vtxinwit[0].scriptWitness,
8383
flags,
84-
MutableTransactionNoWithdrawsSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue),
84+
MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue),
8585
&err);
8686
assert(err == SCRIPT_ERR_OK);
8787
assert(success);

0 commit comments

Comments
 (0)