Closed jeff-aion closed 5 years ago
An example of this problem can be seen in the following method.
public static int temp;
public static void compute(int max) {
int c = 2;
int a = 2 ^ 100;
int b = 2 ^ 20;
int a0 = a % c;
int a1 = a / c;
int b0 = b % c;
int b1 = b / c;
while (c < max) {
c = c + 1;
a0 = a % c;
a1 = a / c;
b0 = b % c;
b1 = b / c;
}
int i00 = a0 * b0;
int i01 = a0 * b1;
int i10 = a1 * b0;
int i010 = i01 * c;
int i011 = i01 / c;
int i100 = i10 * c;
int i101 = i10 / c;
int r1 = i100 + i011 + i101;
temp = 1;
}
Calling this on the AVM would consume 93662 nrg. The same code on solidity (with int128) costs 48246 nrg.
Further investigations revealed that the main cost belongs to ABIDecoder's decodeAndRunWithClass; which costs 37234. The actual execution cost for the compute method is 21334. There's a 22988 nrg cost to load the contract and 1268 nrg cost to write to the temp
variable.
Using the ABIGenerator would remove this constant cost from transaction.
Using the ABIGenerator tool compares the method names using avm_equals
in Shadow String
class. This method has a total of 2k fee. So, if the called method is at the end of the contract, there can be a big cost to just find the method.
Additionally, avm_equals
uses the internal avm_length
, which is wrong and increases the total cost.
Returning a value from a contract method would invoke avm_encodeOneObject
. This method allocates a 64 KiB buffer and its cost is really high with he current implementation.
Loading cost is calculated inside the core module using
public static long getBasicTransactionCost(byte[] transactionData) {
int cost = BASIC_COST;
for (byte b : transactionData) {
cost += (b == 0) ? 4 : 64;
}
return cost;
}
Should this be reconsidered?
Calls to BlockchainRuntime
class are very expensive compared to solidity. For example, BlockchainRuntime.getCaller
, BlockchainRuntime.getAddress
, BlockchainRuntime.getOrigin
cost 1300 nrg (100 + 600 + 600).
BigInteger
and BigDecimal
internal constructors have a fee of 100. This cost for creating an object can be removed. Another consideration is whether to add a linear cost to methods of these classes.
AVM contracts currently run a higher energy cost than similar Solidity counterparts. Relatively little of this is a real cost and is generally just that we have done little to analyze the values we are charging. I suspect that this will continue to be refined in future hard-forks but there are a few points we should at least quickly investigate, prior to this initial release:
Execution and memory costs are really just to avoid denial of service, so fitting them into this unified model we inherited from Ethereum is always going to be rough.