Coverage Summary for Class: RemascContract (co.rsk.remasc)
Class |
Class, %
|
Method, %
|
Line, %
|
RemascContract |
0%
(0/1)
|
0%
(0/11)
|
0%
(0/55)
|
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.remasc;
20
21 import co.rsk.config.RemascConfig;
22 import co.rsk.core.RskAddress;
23 import co.rsk.panic.PanicProcessor;
24 import co.rsk.rpc.modules.trace.ProgramSubtrace;
25 import org.ethereum.config.Constants;
26 import org.ethereum.config.blockchain.upgrades.ActivationConfig;
27 import org.ethereum.core.Block;
28 import org.ethereum.core.CallTransaction;
29 import org.ethereum.core.Repository;
30 import org.ethereum.core.Transaction;
31 import org.ethereum.db.BlockStore;
32 import org.ethereum.db.ByteArrayWrapper;
33 import org.ethereum.db.ReceiptStore;
34 import org.ethereum.util.ByteUtil;
35 import org.ethereum.vm.DataWord;
36 import org.ethereum.vm.LogInfo;
37 import org.ethereum.vm.PrecompiledContracts;
38 import org.ethereum.vm.exception.VMException;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import java.lang.reflect.InvocationTargetException;
43 import java.lang.reflect.Method;
44 import java.util.Arrays;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.Map;
48
49 /**
50 * The Remasc contract which manages the distribution of miner fees.
51 * This class just extends PrecompiledContract, checks no wrong data was supplied and delegates to
52 * Remasc the actual fee distribution logic
53 * @author Oscar Guindzberg
54 */
55 public class RemascContract extends PrecompiledContracts.PrecompiledContract {
56
57 private static final Logger logger = LoggerFactory.getLogger(RemascContract.class);
58 private static final PanicProcessor panicProcessor = new PanicProcessor();
59
60 private static final CallTransaction.Function PROCESS_MINERS_FEES = CallTransaction.Function.fromSignature("processMinersFees", new String[]{}, new String[]{});
61 public static final CallTransaction.Function GET_STATE_FOR_DEBUGGING = CallTransaction.Function.fromSignature("getStateForDebugging", new String[]{}, new String[]{"bytes"});
62
63 public static final DataWord MINING_FEE_TOPIC = DataWord.fromString("mining_fee_topic");
64 public static final String REMASC_CONFIG = "remasc.json";
65
66 private final Constants constants;
67 private final ActivationConfig activationConfig;
68 private final RemascConfig remascConfig;
69
70 private final Map<ByteArrayWrapper, CallTransaction.Function> functions;
71 private Remasc remasc;
72
73 public RemascContract(RskAddress contractAddress, RemascConfig remascConfig, Constants constants, ActivationConfig activationConfig) {
74 this.constants = constants;
75 this.activationConfig = activationConfig;
76 this.remascConfig = remascConfig;
77 this.contractAddress = contractAddress;
78 this.functions = new HashMap<>();
79 this.functions.put(new ByteArrayWrapper(PROCESS_MINERS_FEES.encodeSignature()), PROCESS_MINERS_FEES);
80 this.functions.put(new ByteArrayWrapper(GET_STATE_FOR_DEBUGGING.encodeSignature()), GET_STATE_FOR_DEBUGGING);
81 }
82
83 @Override
84 public long getGasForData(byte[] data) {
85 // changes here?
86 return 0;
87 }
88
89 @Override
90 public void init(Transaction executionTx, Block executionBlock, Repository repository, BlockStore blockStore, ReceiptStore receiptStore, List<LogInfo> logs) {
91 this.remasc = new Remasc(constants, activationConfig, repository, blockStore, remascConfig, executionTx, contractAddress, executionBlock, logs);
92 }
93
94 @Override
95 public List<ProgramSubtrace> getSubtraces() {
96 return this.remasc.getSubtraces();
97 }
98
99 @Override
100 public byte[] execute(byte[] data) throws VMException {
101 try {
102 CallTransaction.Function function = this.getFunction(data);
103 Method m = this.getClass().getMethod(function.name);
104 Object result = this.invoke(m);
105 remasc.save();
106 return this.encodeResult(function, result);
107 } catch(RemascInvalidInvocationException ex) {
108 // Remasc contract was invoked with invalid parameters / out of place, throw VMException to avoid funds being transferred
109 logger.warn(ex.getMessage(), ex);
110 throw new VMException(ex.getMessage());
111 } catch(Exception ex) {
112 logger.error(ex.getMessage(), ex);
113 panicProcessor.panic("remascExecute", ex.getMessage());
114
115 throw new VMException("Exception executing remasc", ex);
116 }
117 }
118
119 public void processMinersFees() throws Exception {
120 logger.trace("processMinersFees");
121
122 remasc.processMinersFees();
123 }
124
125 public byte[] getStateForDebugging() throws Exception {
126 logger.trace("getStateForDebugging");
127
128 return remasc.getStateForDebugging().getEncoded();
129 }
130
131 private CallTransaction.Function getFunction(byte[] data) {
132 CallTransaction.Function function;
133
134 if (data == null || data.length == 0) {
135 function = PROCESS_MINERS_FEES;
136 } else {
137 if (data.length != 4) {
138 logger.warn("Invalid function: signature longer than expected {}.", ByteUtil.toHexString(data));
139 throw new RemascInvalidInvocationException("Invalid function signature");
140 }
141
142 byte[] functionSignature = Arrays.copyOfRange(data, 0, 4);
143 function = functions.get(new ByteArrayWrapper(functionSignature));
144
145 if (function == null) {
146 logger.warn("Invalid function: signature does not match an existing function {}.", ByteUtil.toHexString(functionSignature));
147 throw new RemascInvalidInvocationException("Invalid function signature");
148 }
149 }
150 return function;
151 }
152
153 private Object invoke(Method m) throws InvocationTargetException, IllegalAccessException {
154 try {
155 return m.invoke(this);
156 } catch (InvocationTargetException ite) {
157 if (ite.getTargetException() instanceof RemascInvalidInvocationException) {
158 logger.warn(ite.getTargetException().getMessage(), ite.getTargetException());
159 throw (RemascInvalidInvocationException) ite.getTargetException();
160 } else {
161 throw ite;
162 }
163 }
164 }
165
166 private byte[] encodeResult(CallTransaction.Function function, Object result) {
167 if (result == null) {
168 return new byte[0];
169 }
170
171 return function.encodeOutputs(result);
172 }
173 }