Error when performing dryRun (Lima v5.0.0-rc.2)

I am currently working on preparing our Java SDK for the upcoming Lima hardfork. I always get Error: illegal_contract_compiler_version when performing a dryRun.

The given transaction is being built with abiVersion 1 and vmVersion 6.

The contract is being compiled with compiler version v3.2.0.

Anyone able to help me out? Is it necessary to compile the contract with v4.x.x? But this would require additional changes in my contract which I wasn’t able to solve immediately.

Yes, the error Error: illegal_contract_compiler_version means that you are trying to use bytecode compiled with an older compiler (3.x) on Lima (or a newer 4.x compiler on Fortuna, it is the same error but not applicable in this case).

The reason you need the new compiler for Lima is that we have added the payable modifier, and the compiler needs to insert appropriate information about this.

1 Like

thanks. after making required changes in the tuple-definition the compiler returns an internal server error using this contract:

contract PaymentSplitter =
   record state =
      {  owner: address,
         recipientConditions: map(address, int), // map of recipients with percentage to receive (value between 1 and 100)
         totalAmountSplitted: int }

   // CONTRACT EVENTS
   datatype event = AddingInitialRecipients()
      | RecipientAdded(indexed address, indexed int)
      | AddressUpdated(indexed address, indexed address)
      | UpdatingAllRecipients()
      | PaymentReceivedAndSplitted(indexed address, indexed int, indexed int)

   // CONSTRUCTOR
   entrypoint init(recipientConditions': map(address, int)) : state =
      require(sumWeights(recipientConditions') == 100, "sum of weights needs to be 100")
      Chain.event(AddingInitialRecipients)
      {  owner = Call.caller,
         recipientConditions = recipientConditions',
         totalAmountSplitted = 0}

   // READ ONLY FUNCTIONS

   entrypoint getOwner() : address =
      state.owner

   entrypoint getRecipientsCount() : int =
      Map.size(state.recipientConditions)

   entrypoint isRecipient(who': address) : bool =
      Map.member(who', state.recipientConditions)

   entrypoint getWeight(who': address) : int =
      Map.lookup_default(who', state.recipientConditions, 0)

   entrypoint getTotalAmountSplitted() : int =
      state.totalAmountSplitted

   // PAY-AND-SPLIT FUNCTION
   stateful entrypoint payAndSplit() =
      require(Contract.balance > 0, "contract didn't receive any payment")
      let recipientConditions: list(address * int) = Map.to_list(state.recipientConditions)
      put(state{totalAmountSplitted = Contract.balance + state.totalAmountSplitted})
      split(recipientConditions, Contract.balance)
      Chain.event(PaymentReceivedAndSplitted(Call.caller, Call.value, Contract.balance))

   // STATEFUL FUNCTIONS

   stateful entrypoint transferOwnership(newOwner': address) =
      onlyOwner()
      put(state{owner = newOwner'})

   stateful entrypoint updateAddress(oldAddress': address, newAddress': address) =
      onlyOwnerOrRecipient(oldAddress')
      let weight: int = state.recipientConditions[oldAddress']
      put(state{recipientConditions @ rc = Map.delete(oldAddress', rc)}) // remove old address
      put(state{recipientConditions[newAddress'] = weight}) // add new address
      Chain.event(AddressUpdated(oldAddress', newAddress'))

   stateful entrypoint updateRecipientConditions(recipients': map(address, int)) =
      onlyOwner()
      Chain.event(UpdatingAllRecipients)
      require(sumWeights(recipients') == 100, "sum of weights needs to be 100")
      put(state{recipientConditions = recipients'})
      fireRecipientAddedEvents(Map.to_list(state.recipientConditions))

   // PRIVATE FUNCTIONS

   function onlyOwner() =
      require(Call.caller == state.owner, "caller must be the owner")

   function onlyOwnerOrRecipient(recipient': address) =
      require(Call.caller == state.owner || Call.caller == recipient', "caller must be the owner or the recipient")

   function sumWeights(recipients': map(address, int)) : int =
      let recipientList: list(address * int) = Map.to_list(recipients')
      let intList: list(int) = map(pair_second, recipientList)
      sum(intList, (x) => x)

   function fireRecipientAddedEvents(recipientConditions': list(address * int)) =
      switch(recipientConditions')
         [] => ()
         (recipient, weight) :: l' =>
            Chain.event(RecipientAdded(recipient, weight))

   stateful function split(recipientConditions': list(address * int), totalValue: int) =
      switch(recipientConditions')
         [] => ()
         (recipient, weight) :: l' =>
            Chain.spend(recipient, totalValue / 100 * weight)
            split(l', totalValue)

   // GENERIC HELPER FUNCTIONS

   function map(f : 'a => 'b, l : list('a)) : list('b) =
      switch(l)
         [] => []
         e :: l' => f(e) :: map(f, l')

   function foldr(f : (('a, 'b) => 'b), z: 'b, l : list('a)) : 'b =
      switch(l)
         [] => z
         e :: l' => f(e, foldr(f, z, l'))

   function sum(l : list('a), f : 'a => int) : int =
      foldr((x, y) => x + y, 0, map(f, l))

   function pair_second(tuple) =
      switch(tuple)
         (_, e) => e

can you tell me what could be wrong here?

Hmm, it compiles just fine for me… Which compiler are you using? v4.0.0-rc5 is the latest and greatest…

you are right. I looked at the wrong line. it seems like the calldata now needs to be provided differently. the internal server error comes when trying to encode the calldata :smiley:

currently I am providing an array with 1 argument in the calldata. the argument looks like this:

{[ak_RPAwsPcdxzuBhEtwqdHQquKmdFFSY8M9myS4EaaTWbwEoUnS5] = 20, [ak_2feoWo2kTqv5Lb175vtPFFTQp6vGbme2GAbfM5EZqxVR549xWK] = 40, [ak_2JZC7Ynsr38XGxZqKHYCojPzTpb8dSZMTBsJZJoSGJuKD134Jy] = 40}

how should the argument look like for the init function?

edit

  • I am using compiler version v.4.0.0-rc5

That looks correct as well, I’m off until tonight, so I can’t check it right now.

Are you using the HTTP-compiler front-end or the command line?

so your message is that the format of providing calldata didn’t change, right?

we are running against a local hosted compiler and talking to the API.

Going from v3 to v4 :thinking: I think there are a few new options, check the changelog of aesophia_http and the swagger file for details.

I’ve got no problems producing the call-data using the latest aesophia_http docker image:

aeternity: cat /tmp/foo.aes 
contract Test =
  record state = { m : map(address, int) }
  entrypoint init(m_ : map(address, int)) = { m = m_ }
aeternity: csource=`cat /tmp/foo.aes`
aeternity: curl -H "Content-Type: application/json" -d "{\"function\":\"init\",\"arguments\":[\"{[ak_RPAwsPcdxzuBhEtwqdHQquKmdFFSY8M9myS4EaaTWbwEoUnS5] = 20, [ak_2feoWo2kTqv5Lb175vtPFFTQp6vGbme2GAbfM5EZqxVR549xWK] = 40, [ak_2JZC7Ynsr38XGxZqKHYCojPzTpb8dSZMTBsJZJoSGJuKD134Jy] = 40}\"],\"source\":\"$csource\",\"options\":{\"backend\":\"fate\"}}" -X POST http://localhost:3080/encode-calldata
{"calldata":"cb_KxFE1kQfGy8DnwCgN1zoUO0byvTdsEGbIVD9iEbIAIe7/ec2Np01s2IrHTAonwCgq46TKoipZr6WylwiPLkZ8vokHc5/fDP07GimDU15tvVQnwCg23Wq+Qk3svHNcS7oSB1V6JSgluUS1eKDRp7QsU/3D8hQiQ/W6A=="}

But, the same example produces an error in the CLI front-end of the compiler :disappointed:

aeternity: ./aesophia_cli --create_calldata /tmp/foo.aes --calldata_fun init --calldata_args "{[ak_RPAwsPcdxzuBhEtwqdHQquKmdFFSY8M9myS4EaaTWbwEoUnS5] = 60,  [ak_2feoWo2kTqv5Lb175vtPFFTQp6vGbme2GAbfM5EZqxVR549xWK] = 40}"

Parse error at line 7, col 2:
Unexpected indentation. Probable causes:
  - something is missing in the previous statement, or
  - this line should be indented more.

We will make sure that is fixed before the final 4.0.0 version is released.

I believe the only thing missing is the “backend” option, in the compiler v4.x series yo have to specify which backend you want to use: fate or aevm.If none is specified the compiler returns an error.

here is a sample request (from @hanssv.chain example)

POST https://compiler.aepps.com/encode-calldata
Content-Type: application/json
Sophia-Compiler-Version: 4.0.0-rc5

{
    "function": "init",
    "arguments": [
        "{[ak_RPAwsPcdxzuBhEtwqdHQquKmdFFSY8M9myS4EaaTWbwEoUnS5] = 20, [ak_2feoWo2kTqv5Lb175vtPFFTQp6vGbme2GAbfM5EZqxVR549xWK] = 40, [ak_2JZC7Ynsr38XGxZqKHYCojPzTpb8dSZMTBsJZJoSGJuKD134Jy] = 40}"
    ],
    "source": "contract Test =\n    record state = { m : map(address, int) } \n    entrypoint init(m_ : map(address, int)) = { m = m_ }",
    "options": {
        "backend": "fate"
    }
}

and the result using fate:

HTTP/1.1 200 OK
Content-Length: 182
Content-Type: application/json
Date: Fri, 04 Oct 2019 07:22:23 GMT
Server: Cowboy
Vary: Accept-Encoding
Connection: close

{
  "calldata": "cb_KxFE1kQfGy8DnwCgN1zoUO0byvTdsEGbIVD9iEbIAIe7/ec2Np01s2IrHTAonwCgq46TKoipZr6WylwiPLkZ8vokHc5/fDP07GimDU15tvVQnwCg23Wq+Qk3svHNcS7oSB1V6JSgluUS1eKDRp7QsU/3D8hQiQ/W6A=="
}

and aevm:

HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: application/json
Date: Fri, 04 Oct 2019 07:24:49 GMT
Server: Cowboy
Vary: Accept-Encoding
Content-Length: 254
Connection: close

{
  "calldata": "cb_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAwL/1cQIrYKi4PYb+8VX9C4UVfgoJVPy3WaoMHziQz3wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgN1zoUO0byvTdsEGbIVD9iEbIAIe7/ec2Np01s2IrHTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCrjpMqiKlmvpbKXCI8uRny+iQdzn98M/TsaKYNTXm29QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAINt1qvkJN7LxzXEu6EgdVeiUoJblEtXig0ae0LFP9w/IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKHMw6E0="
}
1 Like

thats a good hint. probably this is the problem. will check and inform you about it. thanks!

@hanssv.chain @noandrea:

after adding the compiler-options I am able to deploy the contract and call the payAndSplit-function. but it seems like the functionality of the contract is broken. somehow the amount is not splitted across the given accounts in the init function. this is really strange! … the only thing I changed in the contract is the syntax regarding tuples.

How do you observe that it doesn’t work? Is the funds split in some other way, or not at all?

None of the functions is payable, and neither is the contract so I’m not sure how it is supposed to work?

1 Like

again didn’t catch that :sweat_smile: forgot about the introduction of payable. now it works as expected. thanks!

@hanssv.chain I made all required changes and now we provide an easy selection between FATE and AEVM in our SDK.

with AEVM we have no problems. when using FATE then the dryRun is failing for the payAndSplit-function. (Internal Server Error)

the dryRun for the init-function works without any problems.

this seems to be a problem in the implementation of the core-protocol I think. will look into the debug-log and hopefully find more information about the problem.

edit
here the error-log of the node. I hope this is related to the dryRun for the payAndSplit-function:

2019-10-06 14:02:08.774 [error] <0.5465.1>@aec_trees:apply_txs_on_state_trees:607 Tx {aetx,contract_call_tx,aect_call_tx,109,{contract_call_tx,{id,account,<<117,238,152,37,173,99,9,99,72,43,177,147,154,33,42,14,83,88,131,198,180,215,128,78,64,40,126,31,85,109,162,114>>},2,{id,contract,<<62,44,231,91,214,95,57,42,226,167,63,31,25,1,27,108,118,168,104,112,152,92,209,4,53,78,77,169,17,129,176,177>>},3,452180000000000,0,1000000000000000000,1579000,1000000000,<<43,17,245,174,169,217,63>>,[],<<117,238,152,37,173,99,9,99,72,43,177,147,154,33,42,14,83,88,131,198,180,215,128,78,64,40,126,31,85,109,162,114>>}} cannot be applied due to an error {error,{badmatch,{es,void,[],#{0 => [{'PUSH',{immediate,0}},{'BALANCE',{stack,0}},{'GT',{stack,0},{stack,0},{stack,0}},{'JUMPIF',{stack,0},{immediate,4}}],1 => [{'PUSH',{immediate,<<"contract didn't receive any payment">>}},{'ABORT',{stack,0}}],2 => [{'STORE',{var,9999},{stack,0}},{'ELEMENT',{stack,0},{immediate,1},{var,-1}},{'MAP_TO_LIST',{var,1},{stack,0}},{'ELEMENT',{stack,0},{immediate,2},{var,-1}},{'BALANCE',{stack,0}},{'ADD',{stack,0},{stack,0},{stack,0}},{'PUSH',{var,-1}},{'SETELEMENT',{stack,0},{immediate,2},{stack,0},{stack,0}},{'STORE',{var,-1},{stack,0}},{'BALANCE',{stack,0}},{'PUSH',{var,1}},{'CALL',{immediate,<<48,129,120,71>>}}],3 => [{'STORE',{var,9999},{stack,0}},{'CALLER',{stack,0}},{'CALL_VALUE',{stack,0}},{'BALANCE',{stack,0}},{'VARIANT',{stack,0},{immediate,[0,2,2,0,3]},{immediate,4},{immediate,3}},{'CALL_T',{immediate,<<101,165,224,15>>}}],4 => [{'PUSH',{immediate,{tuple,{}}}},{'JUMP',{immediate,2}}]},[],{address,<<117,238,152,37,173,99,9,99,72,43,177,147,154,33,42,14,83,88,131,198,180,215,128,78,64,40,126,31,85,109,162,114>>},1000000000000000000,{state,{state,{trees,{mpt,<<171,228,5,15,89,141,152,193,101,156,117,113,162,178,91,110,54,52,159,46,19,34,192,133,31,198,187,103,190,49,4,48>>,{db,accounts,{gb_trees,{6,{<<117,136,145,167,177,0,60,195,178,67,231,39,105,236,45,30,70,137,18,208,152,213,107,232,95,253,233,255,72,9,210,169>>,[<<48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1>>,<<205,10,1,0,137,54,53,201,173,197,222,160,0,0>>],{<<76,143,150,212,192,14,37,167,216,214,98,59,47,140,151,175,190,28,43,95,35,188,196,210,230,109,18,87,182,79,154,198>>,[<<117,136,145,167,177,0,60,195,178,67,231,39,105,236,45,30,70,137,18,208,152,213,107,232,95,253,233,255,72,9,210,169>>,<<>>,<<>>,<<206,6,103,203,1,140,194,39,195,15,159,222,218,167,21,216,239,251,15,116,4,47,120,248,242,174,10,199,1,239,42,155>>,<<>>,<<>>,<<>>,<<194,185,119,83,16,122,56,160,194,30,34,5,112,247,64,40,84,60,24,86,25,12,136,207,154,162,176,127,14,119,222,166>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>],{<<42,145,88,134,154,134,84,70,138,13,167,218,43,216,79,207,241,241,224,38,204,66,67,162,14,228,244,111,33,172,202,181>>,[<<53,238,152,37,173,99,9,99,72,43,177,147,154,33,42,14,83,88,131,198,180,215,128,78,64,40,126,31,85,109,162,114>>,<<210,10,1,2,142,4,238,45,109,65,91,133,165,71,57,120,226,36,0>>],nil,nil},nil},{<<196,236,139,84,213,10,252,221,235,68,7,110,56,191,2,91,204,167,133,153,157,129,30,107,145,207,87,3,179,23,30,145>>,[<<117,136,145,167,177,0,60,195,178,67,231,39,105,236,45,30,70,137,18,208,152,213,107,232,95,253,233,255,72,9,210,169>>,<<>>,<<>>,<<206,6,103,203,1,140,194,39,195,15,159,222,218,167,21,216,239,251,15,116,4,47,120,248,242,174,10,199,1,239,42,155>>,<<>>,<<>>,<<>>,<<42,145,88,134,154,134,84,70,138,13,167,218,43,216,79,207,241,241,224,38,204,66,67,162,14,228,244,111,33,172,202,181>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>,<<>>],{<<145,157,68,129,85,57,130,68,39,17,179,160,136,125,125,130,254,150,3,14,14,158,214,1,209,43,35,133,248,215,254,178>>,[<<62,44,231,91,214,95,57,42,226,167,63,31,25,1,27,108,118,168,104,112,152,92,209,4,53,78,77,169,17,129,176,177>>,<<204,10,1,0,136,13,224,182,179,167,100,0,0>>],nil,{<<171,228,5,15,89,141,152,193,101,156,117,113,162,178,91,110,54,52,159,46,19,34,192,133,31,198,187,103,190,49,4,48>>,[<<117,136,145,167,177,0,60,195,178,67,231,39,105,236,45,30,70,137,18,208,152,213,107,232,95,253,233,255,72,9,210,169>>,<<>>,<<>>,<<145,157,68,129,85,57,130,68,39,17,179,160,136,125,125,130,254,...>>,...],...}},...}}}},...}},...},...},...},...}}}
2019-10-06 14:02:08.775 [error] <0.5465.1>@lists:thing_to_list:603 CRASH REPORT Process <0.5465.1> with 0 neighbours crashed with reason: no function clause matching lists:thing_to_list({error,{badmatch,{es,void,[],#{0 => [{'PUSH',{immediate,0}},{'BALANCE',{stack,0}},{'GT',{stack,...},...},...],...},...}}}) line 603
2019-10-06 14:02:08.775 [error] <0.5465.1>@lists:thing_to_list:603 Cowboy stream 1 with ranch listener internal and connection process <0.5464.1> had its request process exit with reason: no function clause matching lists:thing_to_list({error,{badmatch,{es,void,[],#{0 => [{'PUSH',{immediate,0}},{'BALANCE',{stack,0}},{'GT',{stack,...},...},...],...},...}}}) line 603

we are using this version of the PaymentSplitter contract:

the node-version we are running against is v5.0.0-rc.3

1 Like

I can’t reproduce the problem. What is the failing dryRun transaction?

We experimented a bit more, and finally managed to reproduce the issue.

It looks to be a problem with Map.to_list in FATE - we’ll investigate further.

3 Likes

hopefully not a big deal. I guess it will be fixed in the next release candidate :slight_smile:

@erik.chain isn’t this observation worth a bug bounty? :stuck_out_tongue:

1 Like

It is fixed already - 5.0.0-rc4 has been out for several hours :slight_smile:

2 Likes

the problem I mentioned has been fixed with 5.0.0-rc4. but I probably got another issue regarding the FATE-VM.

it seems like for the contract:

contract Identity =
  entrypoint main(z : int) = z

when calling the main-function with following calldata (value 42):

cb_KxG4F37sG1Q/+F7e

and afterwards waiting for the TxInfoObject we get for both (returnValue and returnType) the same content:

cb_VNLOFXc=

when trying to decode this with the compiler providing cb_VNLOFXc= as body and int as sophiaType we get a Bad Request with following responseBody:

[{"message":"bad type/data","pos":{"col":0,"line":0},"type":"data_error"}]

are we doing sth wrong? can you check that? doing the same using AEVM works without any problem.

edit:

  • assuming the node response is correct (although returnType of the TxInfoObject should be ‘ok’, ‘error’ or ‘revert’) then this is probably a problem in the compiler when trying to decode cb_VNLOFXc= as sophiaType int.