aionnetwork / AVM

Enabling Java code to run in a blockchain environment
https://theoan.com/
MIT License
49 stars 25 forks source link

Update billing mechanism to reflect similar effort from Solidity applications #376

Closed jeff-aion closed 5 years ago

jeff-aion commented 5 years ago

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.

aion-shidokht commented 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.

aion-shidokht commented 5 years ago

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.

aion-shidokht commented 5 years ago

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.

aion-shidokht commented 5 years ago

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?

aion-shidokht commented 5 years ago

Calls to BlockchainRuntime class are very expensive compared to solidity. For example, BlockchainRuntime.getCaller, BlockchainRuntime.getAddress, BlockchainRuntime.getOrigin cost 1300 nrg (100 + 600 + 600).

aion-shidokht commented 5 years ago

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.