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 }