Coverage Summary for Class: BridgeEventLoggerImpl (co.rsk.peg.utils)

Class Class, % Method, % Line, %
BridgeEventLoggerImpl 0% (0/1) 0% (0/25) 0% (0/113)


1 /* 2  * This file is part of RskJ 3  * Copyright (C) 2017 RSK Labs Ltd. 4  * 5  * This program is free software: you can redistribute it and/or modify 6  * it under the terms of the GNU Lesser General Public License as published by 7  * the Free Software Foundation, either version 3 of the License, or 8  * (at your option) any later version. 9  * 10  * This program is distributed in the hope that it will be useful, 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13  * GNU Lesser General Public License for more details. 14  * 15  * You should have received a copy of the GNU Lesser General Public License 16  * along with this program. If not, see <http://www.gnu.org/licenses/>. 17  */ 18  19 package co.rsk.peg.utils; 20  21 import co.rsk.bitcoinj.core.Address; 22 import co.rsk.bitcoinj.core.BtcECKey; 23 import co.rsk.bitcoinj.core.BtcTransaction; 24 import co.rsk.bitcoinj.core.Coin; 25 import co.rsk.config.BridgeConstants; 26 import co.rsk.core.RskAddress; 27 import co.rsk.peg.Bridge; 28 import co.rsk.peg.BridgeEvents; 29 import co.rsk.peg.Federation; 30 import org.ethereum.config.blockchain.upgrades.ActivationConfig; 31 import org.ethereum.config.blockchain.upgrades.ConsensusRule; 32 import org.ethereum.core.Block; 33 import org.ethereum.core.CallTransaction; 34 import org.ethereum.core.Transaction; 35 import org.ethereum.crypto.ECKey; 36 import org.ethereum.util.ByteUtil; 37 import org.ethereum.util.RLP; 38 import org.ethereum.vm.DataWord; 39 import org.ethereum.vm.LogInfo; 40 import org.ethereum.vm.PrecompiledContracts; 41  42 import java.util.Collections; 43 import java.util.List; 44 import java.util.function.Function; 45 import java.util.stream.Collectors; 46  47 /** 48  * Responsible for logging events triggered by BridgeContract. 49  * 50  * @author martin.medina 51  */ 52 public class BridgeEventLoggerImpl implements BridgeEventLogger { 53  54  private static final byte[] BRIDGE_CONTRACT_ADDRESS = PrecompiledContracts.BRIDGE_ADDR.getBytes(); 55  56  private final BridgeConstants bridgeConstants; 57  private final ActivationConfig.ForBlock activations; 58  59  private List<LogInfo> logs; 60  61  public BridgeEventLoggerImpl(BridgeConstants bridgeConstants, ActivationConfig.ForBlock activations, List<LogInfo> logs) { 62  this.bridgeConstants = bridgeConstants; 63  this.activations = activations; 64  this.logs = logs; 65  } 66  67  public void logUpdateCollections(Transaction rskTx) { 68  if (activations.isActive(ConsensusRule.RSKIP146)) { 69  logUpdateCollectionsInSolidityFormat(rskTx); 70  } else { 71  logUpdateCollectionsInRLPFormat(rskTx); 72  } 73  } 74  75  private void logUpdateCollectionsInSolidityFormat(Transaction rskTx) { 76  CallTransaction.Function event = BridgeEvents.UPDATE_COLLECTIONS.getEvent(); 77  byte[][] encodedTopicsInBytes = event.encodeEventTopics(); 78  List<DataWord> encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); 79  byte[] encodedData = event.encodeEventData(rskTx.getSender().toString()); 80  81  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); 82  } 83  84  private void logUpdateCollectionsInRLPFormat(Transaction rskTx) { 85  this.logs.add( 86  new LogInfo(BRIDGE_CONTRACT_ADDRESS, 87  Collections.singletonList(Bridge.UPDATE_COLLECTIONS_TOPIC), 88  RLP.encodeElement(rskTx.getSender().getBytes()) 89  ) 90  ); 91  } 92  93  public void logAddSignature(BtcECKey federatorPublicKey, BtcTransaction btcTx, byte[] rskTxHash) { 94  if (activations.isActive(ConsensusRule.RSKIP146)) { 95  ECKey key = ECKey.fromPublicOnly(federatorPublicKey.getPubKey()); 96  String federatorRskAddress = ByteUtil.toHexString(key.getAddress()); 97  logAddSignatureInSolidityFormat(rskTxHash, federatorRskAddress, federatorPublicKey); 98  } else { 99  logAddSignatureInRLPFormat(federatorPublicKey, btcTx, rskTxHash); 100  } 101  } 102  103  private void logAddSignatureInSolidityFormat(byte[] rskTxHash, String federatorRskAddress, BtcECKey federatorPublicKey) { 104  CallTransaction.Function event = BridgeEvents.ADD_SIGNATURE.getEvent(); 105  byte[][] encodedTopicsInBytes = event.encodeEventTopics(rskTxHash, federatorRskAddress); 106  List<DataWord> encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); 107  byte[] encodedData = event.encodeEventData(federatorPublicKey.getPubKey()); 108  109  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); 110  } 111  112  private void logAddSignatureInRLPFormat(BtcECKey federatorPublicKey, BtcTransaction btcTx, byte[] rskTxHash) { 113  List<DataWord> topics = Collections.singletonList(Bridge.ADD_SIGNATURE_TOPIC); 114  byte[] data = RLP.encodeList(RLP.encodeString(btcTx.getHashAsString()), 115  RLP.encodeElement(federatorPublicKey.getPubKeyHash()), 116  RLP.encodeElement(rskTxHash)); 117  118  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, topics, data)); 119  } 120  121  public void logReleaseBtc(BtcTransaction btcTx, byte[] rskTxHash) { 122  if (activations.isActive(ConsensusRule.RSKIP146)) { 123  logReleaseBtcInSolidityFormat(btcTx, rskTxHash); 124  } else { 125  logReleaseBtcInRLPFormat(btcTx); 126  } 127  } 128  129  private void logReleaseBtcInSolidityFormat(BtcTransaction btcTx, byte[] rskTxHash) { 130  CallTransaction.Function event = BridgeEvents.RELEASE_BTC.getEvent(); 131  byte[][] encodedTopicsInBytes = event.encodeEventTopics(rskTxHash); 132  List<DataWord> encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); 133  byte[] encodedData = event.encodeEventData(btcTx.bitcoinSerialize()); 134  135  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); 136  } 137  138  private void logReleaseBtcInRLPFormat(BtcTransaction btcTx) { 139  List<DataWord> topics = Collections.singletonList(Bridge.RELEASE_BTC_TOPIC); 140  byte[] data = RLP.encodeList(RLP.encodeString(btcTx.getHashAsString()), RLP.encodeElement(btcTx.bitcoinSerialize())); 141  142  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, topics, data)); 143  } 144  145  public void logCommitFederation(Block executionBlock, Federation oldFederation, Federation newFederation) { 146  if (activations.isActive(ConsensusRule.RSKIP146)) { 147  logCommitFederationInSolidityFormat(executionBlock, oldFederation, newFederation); 148  } else { 149  logCommitFederationInRLPFormat(executionBlock, oldFederation, newFederation); 150  } 151  } 152  153  private void logCommitFederationInRLPFormat(Block executionBlock, Federation oldFederation, Federation newFederation) { 154  List<DataWord> topics = Collections.singletonList(Bridge.COMMIT_FEDERATION_TOPIC); 155  156  byte[] oldFedFlatPubKeys = flatKeysAsRlpCollection(oldFederation.getBtcPublicKeys()); 157  byte[] oldFedData = RLP.encodeList(RLP.encodeElement(oldFederation.getAddress().getHash160()), RLP.encodeList(oldFedFlatPubKeys)); 158  159  byte[] newFedFlatPubKeys = flatKeysAsRlpCollection(newFederation.getBtcPublicKeys()); 160  byte[] newFedData = RLP.encodeList(RLP.encodeElement(newFederation.getAddress().getHash160()), RLP.encodeList(newFedFlatPubKeys)); 161  162  long newFedActivationBlockNumber = executionBlock.getNumber() + this.bridgeConstants.getFederationActivationAge(); 163  164  byte[] data = RLP.encodeList(oldFedData, newFedData, RLP.encodeString(Long.toString(newFedActivationBlockNumber))); 165  166  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, topics, data)); 167  } 168  169  private void logCommitFederationInSolidityFormat(Block executionBlock, Federation oldFederation, Federation newFederation) { 170  // Convert old federation public keys in bytes array 171  byte[] oldFederationFlatPubKeys = flatKeysAsByteArray(oldFederation.getBtcPublicKeys()); 172  String oldFederationBtcAddress = oldFederation.getAddress().toBase58(); 173  byte[] newFederationFlatPubKeys = flatKeysAsByteArray(newFederation.getBtcPublicKeys()); 174  String newFederationBtcAddress = newFederation.getAddress().toBase58(); 175  long newFedActivationBlockNumber = executionBlock.getNumber() + this.bridgeConstants.getFederationActivationAge(); 176  177  CallTransaction.Function event = BridgeEvents.COMMIT_FEDERATION.getEvent(); 178  byte[][] encodedTopicsInBytes = event.encodeEventTopics(); 179  List<DataWord> encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); 180  181  byte[] encodedData = event.encodeEventData( 182  oldFederationFlatPubKeys, 183  oldFederationBtcAddress, 184  newFederationFlatPubKeys, 185  newFederationBtcAddress, 186  newFedActivationBlockNumber 187  ); 188  189  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); 190  } 191  192  public void logLockBtc(RskAddress receiver, BtcTransaction btcTx, Address senderBtcAddress, Coin amount) { 193  CallTransaction.Function event = BridgeEvents.LOCK_BTC.getEvent(); 194  byte[][] encodedTopicsInBytes = event.encodeEventTopics(receiver.toString()); 195  List<DataWord> encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); 196  197  byte[] encodedData = event.encodeEventData(btcTx.getHash().getBytes(), senderBtcAddress.toString(), amount.getValue()); 198  199  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); 200  } 201  202  public void logPeginBtc(RskAddress receiver, BtcTransaction btcTx, Coin amount, int protocolVersion) { 203  CallTransaction.Function event = BridgeEvents.PEGIN_BTC.getEvent(); 204  byte[][] encodedTopicsInBytes = event.encodeEventTopics(receiver.toString(), btcTx.getHash().getBytes()); 205  List<DataWord> encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); 206  207  byte[] encodedData = event.encodeEventData(amount.getValue(), protocolVersion); 208  209  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); 210  } 211  212  public void logReleaseBtcRequested(byte[] rskTransactionHash, BtcTransaction btcTx, Coin amount) { 213  CallTransaction.Function event = BridgeEvents.RELEASE_REQUESTED.getEvent(); 214  byte[][] encodedTopicsInBytes = event.encodeEventTopics(rskTransactionHash, btcTx.getHash().getBytes()); 215  List<DataWord> encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); 216  byte[] encodedData = event.encodeEventData(amount.getValue()); 217  218  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); 219  } 220  221  public void logRejectedPegin(BtcTransaction btcTx, RejectedPeginReason reason) { 222  CallTransaction.Function event = BridgeEvents.REJECTED_PEGIN.getEvent(); 223  byte[][] encodedTopicsInBytes = event.encodeEventTopics(btcTx.getHash().getBytes()); 224  List<DataWord> encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); 225  226  byte[] encodedData = event.encodeEventData(reason.getValue()); 227  228  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); 229  } 230  231  public void logUnrefundablePegin(BtcTransaction btcTx, UnrefundablePeginReason reason) { 232  CallTransaction.Function event = BridgeEvents.UNREFUNDABLE_PEGIN.getEvent(); 233  byte[][] encodedTopicsInBytes = event.encodeEventTopics(btcTx.getHash().getBytes()); 234  List<DataWord> encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); 235  236  byte[] encodedData = event.encodeEventData(reason.getValue()); 237  238  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); 239  } 240  241  @Override 242  public void logReleaseBtcRequestReceived(String sender, byte[] btcDestinationAddress, Coin amount) { 243  CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED.getEvent(); 244  byte[][] encodedTopicsInBytes = event.encodeEventTopics(sender); 245  List<DataWord> encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); 246  byte[] encodedData = event.encodeEventData(btcDestinationAddress, amount.getValue()); 247  248  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); 249  } 250  251  @Override 252  public void logReleaseBtcRequestRejected(String sender, Coin amount, RejectedPegoutReason reason) { 253  CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_REJECTED.getEvent(); 254  byte[][] encodedTopicsInBytes = event.encodeEventTopics(sender); 255  List<DataWord> encodedTopics = LogInfo.byteArrayToList(encodedTopicsInBytes); 256  byte[] encodedData = event.encodeEventData(amount.getValue(), reason.getValue()); 257  258  this.logs.add(new LogInfo(BRIDGE_CONTRACT_ADDRESS, encodedTopics, encodedData)); 259  } 260  261  private byte[] flatKeys(List<BtcECKey> keys, Function<BtcECKey, byte[]> parser) { 262  List<byte[]> pubKeys = keys.stream() 263  .map(parser) 264  .collect(Collectors.toList()); 265  int pubKeysLength = pubKeys.stream().mapToInt(key -> key.length).sum(); 266  267  byte[] flatPubKeys = new byte[pubKeysLength]; 268  int copyPos = 0; 269  for (byte[] key : pubKeys) { 270  System.arraycopy(key, 0, flatPubKeys, copyPos, key.length); 271  copyPos += key.length; 272  } 273  274  return flatPubKeys; 275  } 276  277  private byte[] flatKeysAsRlpCollection(List<BtcECKey> keys) { 278  return flatKeys(keys, (k -> RLP.encodeElement(k.getPubKey()))); 279  } 280  281  private byte[] flatKeysAsByteArray(List<BtcECKey> keys) { 282  return flatKeys(keys, BtcECKey::getPubKey); 283  } 284 }