33import static com .google .common .base .Preconditions .checkNotNull ;
44
55import co .rsk .bitcoinj .core .BtcTransaction ;
6- import co .rsk .federate .config .PowpegNodeSystemProperties ;
7- import co .rsk .peg .constants .BridgeConstants ;
86import co .rsk .federate .adapter .ThinConverter ;
9- import co .rsk .federate .bitcoin .BitcoinWrapper ;
10- import co .rsk .federate .bitcoin .BlockListener ;
11- import co .rsk .federate .bitcoin .TransactionListener ;
12- import co .rsk .federate .io .BtcToRskClientFileData ;
13- import co .rsk .federate .io .BtcToRskClientFileReadResult ;
14- import co .rsk .federate .io .BtcToRskClientFileStorage ;
7+ import co .rsk .federate .bitcoin .*;
8+ import co .rsk .federate .config .PowpegNodeSystemProperties ;
9+ import co .rsk .federate .io .*;
1510import co .rsk .federate .timing .TurnScheduler ;
1611import co .rsk .net .NodeBlockProcessor ;
1712import co .rsk .panic .PanicProcessor ;
1813import co .rsk .peg .BridgeUtils ;
1914import co .rsk .peg .PegUtilsLegacy ;
20- import co .rsk .peg .federation .Federation ;
21- import co .rsk .peg .federation .FederationMember ;
2215import co .rsk .peg .PeginInformation ;
16+ import co .rsk .peg .bitcoin .BitcoinUtils ;
2317import co .rsk .peg .btcLockSender .BtcLockSender .TxSenderAddressType ;
2418import co .rsk .peg .btcLockSender .BtcLockSenderProvider ;
19+ import co .rsk .peg .constants .BridgeConstants ;
20+ import co .rsk .peg .federation .Federation ;
21+ import co .rsk .peg .federation .FederationMember ;
2522import co .rsk .peg .pegininstructions .PeginInstructionsException ;
2623import co .rsk .peg .pegininstructions .PeginInstructionsProvider ;
2724import com .google .common .annotations .VisibleForTesting ;
2825import com .google .common .collect .Lists ;
2926import java .io .IOException ;
3027import java .time .Clock ;
31- import java .util .ArrayList ;
32- import java .util .Collections ;
33- import java .util .LinkedList ;
34- import java .util .List ;
35- import java .util .Map ;
36- import java .util .Optional ;
37- import java .util .Set ;
38- import java .util .concurrent .Executors ;
39- import java .util .concurrent .ScheduledExecutorService ;
40- import java .util .concurrent .TimeUnit ;
28+ import java .util .*;
29+ import java .util .concurrent .*;
4130import java .util .stream .IntStream ;
4231import javax .annotation .PreDestroy ;
43- import org .bitcoinj .core .Block ;
44- import org .bitcoinj .core .NetworkParameters ;
45- import org .bitcoinj .core .PartialMerkleTree ;
46- import org .bitcoinj .core .Sha256Hash ;
47- import org .bitcoinj .core .StoredBlock ;
48- import org .bitcoinj .core .Transaction ;
49- import org .bitcoinj .core .Utils ;
32+ import org .bitcoinj .core .*;
5033import org .bitcoinj .store .BlockStoreException ;
5134import org .ethereum .config .blockchain .upgrades .ActivationConfig ;
5235import org .ethereum .config .blockchain .upgrades .ConsensusRule ;
@@ -243,13 +226,12 @@ public void updateBridge() {
243226 panicProcessor .panic ("btclock" , e .getMessage ());
244227 }
245228 }
246-
247229 }
248230
249231 @ Override
250232 public void onBlock (Block block ) {
251233 synchronized (this ) {
252- logger .debug ("onBlock {}" , block .getHash ());
234+ logger .debug ("[ onBlock] {}" , block .getHash ());
253235 PartialMerkleTree tree ;
254236 Transaction coinbase = null ;
255237 boolean dataToWrite = false ;
@@ -258,6 +240,7 @@ public void onBlock(Block block) {
258240
259241 if (tx .isCoinBase ()) {
260242 // safe keep the coinbase and move on
243+ logger .debug ("[onBlock] Transaction {} is the coinbase" , tx .getTxId ());
261244 coinbase = tx ;
262245 continue ;
263246 }
@@ -266,57 +249,51 @@ public void onBlock(Block block) {
266249 // this tx is not important move on
267250 continue ;
268251 }
252+ logger .debug ("[onBlock] Found transaction {} that needs to be registered in the Bridge" , tx .getTxId ());
269253
270254 List <Proof > proofs = fileData .getTransactionProofs ().get (tx .getWTxId ());
271255 boolean blockInProofs = proofs .stream ().anyMatch (p -> p .getBlockHash ().equals (block .getHash ()));
272256 if (blockInProofs ) {
273- logger .info ("Proof for tx {} in block {} already stored" , tx , block .getHash ());
257+ logger .info ("[onBlock] Proof for tx {} in block {} already stored" , tx . getTxId () , block .getHash ());
274258 continue ;
275259 }
276260
277261 // Always use the wtxid for the lock transactions
278262 tree = generatePMT (block , tx , tx .hasWitnesses ());
279263 // If the transaction has a witness, then we need to store the coinbase information to inform it
280264 if (tx .hasWitnesses () && !coinbaseRegistered ) {
265+ logger .debug ("[onBlock] Transaction {} has witness, will need to store the coinbase information to inform it" , tx .getTxId ());
281266 // We don't want to generate the PMT with the wtxid for the coinbase
282267 // as it doesn't have a corresponding hash in the witness root
283268 PartialMerkleTree coinbasePmt = generatePMT (block , coinbase , false );
284269 try {
285270 Sha256Hash witnessMerkleRoot = tree .getTxnHashAndMerkleRoot (new ArrayList <>());
286271 CoinbaseInformation coinbaseInformation = new CoinbaseInformation (
287- coinbase ,
288- witnessMerkleRoot ,
289- block .getHash (),
290- coinbasePmt
272+ coinbase ,
273+ witnessMerkleRoot ,
274+ block .getHash (),
275+ coinbasePmt
291276 );
292- // Validate information
293- byte [] witnessReservedValue = coinbaseInformation .getCoinbaseWitnessReservedValue ();
294- if (witnessReservedValue == null ) {
295- logger .error ("block {} with lock segwit tx {} has coinbase with no witness reserved value. Aborting block processing." , block .getHash (), tx .getWTxId ());
296- // Can't register this transaction, it would be rejected by the Bridge
297- return ;
298- }
299- Sha256Hash calculatedWitnessCommitment = Sha256Hash .twiceOf (witnessMerkleRoot .getReversedBytes (), witnessReservedValue );
300- Sha256Hash witnessCommitment = coinbase .findWitnessCommitment ();
301- if (!witnessCommitment .equals (calculatedWitnessCommitment )) {
302- logger .error ("block {} with lock segwit tx {} generated an invalid witness merkle root" , tx .getWTxId (), block .getHash ());
303- // Can't register this transaction, it would be rejected by the Bridge
304- return ;
305- }
277+ validateCoinbaseInformation (coinbaseInformation );
278+
306279 // store the coinbase
307- fileData .getCoinbaseInformationMap ().put (coinbaseInformation .getBlockHash (), coinbaseInformation );
280+ fileData .getCoinbaseInformationMap ().put (
281+ coinbaseInformation .getBlockHash (),
282+ coinbaseInformation
283+ );
284+ logger .debug ("[onBlock] Coinbase information for transaction {} successully stored" , tx .getTxId ());
308285
309286 // Register the coinbase just once per block
310287 coinbaseRegistered = true ;
311288 } catch (Exception e ) {
312- logger .error (e .getMessage (), e );
289+ logger .error ("[onBlock] {}" , e .getMessage ());
313290 // Without a coinbase related to this transaction the Bridge would reject the transaction
314291 return ;
315292 }
316293 }
317294
318295 proofs .add (new Proof (block .getHash (), tree ));
319- logger .info ("New proof for tx {} in block {}" , tx , block .getHash ());
296+ logger .info ("[onBlock] New proof for tx {} in block {}" , tx . getTxId () , block .getHash ());
320297 dataToWrite = true ;
321298 }
322299
@@ -326,17 +303,58 @@ public void onBlock(Block block) {
326303
327304 try {
328305 this .btcToRskClientFileStorage .write (fileData );
329- logger .info ("Stored proofs for block {}" , block .getHash ());
306+ logger .info ("[onBlock] Stored proofs for block {}" , block .getHash ());
330307 } catch (IOException e ) {
331- logger .error (e .getMessage (), e );
308+ logger .error ("[onBlock] {}" , e .getMessage ());
332309 panicProcessor .panic ("btclock" , e .getMessage ());
333310 }
334311 }
335312 }
336313
314+ private void validateCoinbaseInformation (CoinbaseInformation coinbaseInformation ) {
315+ Sha256Hash witnessMerkleRoot = coinbaseInformation .getWitnessRoot ();
316+ byte [] witnessReservedValue = coinbaseInformation .getCoinbaseWitnessReservedValue ();
317+ BtcTransaction coinbaseTransaction = ThinConverter .toThinInstance (
318+ bridgeConstants .getBtcParams (),
319+ coinbaseInformation .getCoinbaseTransaction ()
320+ );
321+
322+ if (witnessReservedValue == null ) {
323+ String message = String .format (
324+ "Block %s with segwit peg-in tx %s has coinbase with no witness reserved value. Aborting block processing." ,
325+ coinbaseInformation .getBlockHash (),
326+ coinbaseTransaction .getHash ()
327+ );
328+ logger .error ("[validateCoinbaseInformation] {}" , message );
329+ throw new IllegalArgumentException (message );
330+ }
331+
332+ co .rsk .bitcoinj .core .Sha256Hash calculatedWitnessCommitment = co .rsk .bitcoinj .core .Sha256Hash .twiceOf (
333+ witnessMerkleRoot .getReversedBytes (),
334+ witnessReservedValue
335+ );
336+
337+ BitcoinUtils .findWitnessCommitment (coinbaseTransaction )
338+ .filter (commitment -> commitment .equals (calculatedWitnessCommitment ))
339+ .orElseThrow (() -> {
340+ String message = String .format (
341+ "Block %s with segwit peg-in tx %s generated an invalid witness merkle root" ,
342+ coinbaseInformation .getBlockHash (),
343+ coinbaseTransaction .getHash ()
344+ );
345+ logger .error ("[validateCoinbaseInformation] {}" , message );
346+ return new IllegalArgumentException (message );
347+ });
348+ logger .debug (
349+ "[validateCoinbaseInformation] Block {} with segwit peg-in tx {} has a valid witness merkle root" ,
350+ coinbaseInformation .getBlockHash (),
351+ coinbaseTransaction .getHash ()
352+ );
353+ }
354+
337355 @ Override
338356 public void onTransaction (Transaction tx ) {
339- logger .debug ("onTransaction {}" , tx .getWTxId ());
357+ logger .debug ("[ onTransaction] {} (wtxid:{})" , tx . getTxId () , tx .getWTxId ());
340358 synchronized (this ) {
341359 this .fileData .getTransactionProofs ().put (tx .getWTxId (), new ArrayList <>());
342360 try {
@@ -425,12 +443,17 @@ protected void markCoinbasesAsReadyToBeInformed(List<Block> informedBlocks) thro
425443 return ;
426444 }
427445 boolean modified = false ;
428- for (Block informedBlock : informedBlocks ) {
446+ for (Block informedBlock : informedBlocks ) {
429447 if (coinbaseInformationMap .containsKey (informedBlock .getHash ())) {
430448 CoinbaseInformation coinbaseInformation = coinbaseInformationMap .get (informedBlock .getHash ());
431449 coinbaseInformation .setReadyToInform (true );
432450 this .fileData .getCoinbaseInformationMap ().put (informedBlock .getHash (), coinbaseInformation );
433451 modified = true ;
452+ logger .debug (
453+ "[markCoinbasesAsReadyToBeInformed] Marked coinbase {} for block {} as ready to be informed" ,
454+ coinbaseInformation .getCoinbaseTransaction ().getTxId (),
455+ informedBlock .getHash ()
456+ );
434457 }
435458 }
436459 if (!modified ) {
0 commit comments