CREDITSCOM / node

Credits Node is the main module that provide an opportunity to run a node and participate in CREDITS blockchain network.
https://developers.credits.com/
GNU Affero General Public License v3.0
151 stars 16 forks source link

Use invokeExternalContract to do a token transfer #23

Open micmac0 opened 5 years ago

micmac0 commented 5 years ago

Describe the bug I created a smartcontract to act as escrow for betting. I do this :

 Object[] params = new Object[] { owner, amount };
 System.out.println("send token to "+owner+", "+amount);

 Object result = invokeExternalContract("GcqTxR4qjHfzmcYGaMeGi7T1fPf414oKzfTjUjAFKuPB", "transfer", params);

Also smartcontract was deployed with these options : @UsingContract(address = "GcqTxR4qjHfzmcYGaMeGi7T1fPf414oKzfTjUjAFKuPB", method = "transfer") in smartcontract before the method i use to call invokeExternalContract

also tried at deployment and execution from client side to specify usedSmartContractsByte with GcqTxR4qjHfzmcYGaMeGi7T1fPf414oKzfTjUjAFKuPB . used like this in client code :

SmartContractInvocationData scData = new SmartContractInvocationData(smartContractDeployData, method,
                    params, usedSmartContractsByte, false);

When I try this method I had : com.credits.client.node.exception.NodeClientException: Credits Node error: state is empty!

from node smartcontract executor issue seems to be located there : https://github.com/CREDITSCOM/ewa/blob/master/sc-api/src/main/java/com/credits/scapi/v0/SmartContract.java#L94 smart contract "GcqTxR4qjHfzmcYGaMeGi7T1fPf414oKzfTjUjAFKuPB" can't be modify

        if (!usedContract.getContractData().isStateCanModify() && !Arrays.equals(
            usedContract.getContractData().getContractState(),
            returnValue.newContractState)) {
            throw new ContractExecutorException("smart contract \"" + contractAddress + "\" can't be modify");
}

I didn t manage to get the error on my node but with previous version I remember the problem seems to be located there :

To Reproduce Here is the initiator wallet I used : https://monitor.credits.com/testnet-r4_2/account/Eyh6ZBiM9D9yyLDwFG7nqAwgm8fFfJn7NauZ6bQxsufn#

here is the smartcontract : https://monitor.credits.com/testnet-r4_2/Contract/5LKBpWvcDXYi4QK9xpx9Mraibj6hqgoai9R6m2Hn1qV3

Additional question Can we transfer token to a smartcontract address ? If so, how can we initiate token transfer token from this same smartcontract as it can t be initiator ?

tkoen93 commented 5 years ago

I've been trying this feature myself and I'm experiencing similar issues as @micmac0

My token contract is: https://monitor.credits.com/testnet-r4_2/contract/6vNF6KMXHqj6UtHgSVYKyf24v4KMRXDC5TzpiMkMUihB

After that I created a simple contract that calls the transfer function via invokeExternalContract (https://monitor.credits.com/testnet-r4_2/Contract/uLesZgD5Hq7RzMwzEEJk1p38MiQTkGaKJvKMg9jpini)

import com.credits.scapi.annotations.*;
import com.credits.scapi.v0.*;

public class simpleContract extends SmartContract {

 public simpleContract() {
 }

@UsingContract(address = "6vNF6KMXHqj6UtHgSVYKyf24v4KMRXDC5TzpiMkMUihB", method = "transfer") 
 public void getValue(String wallet, String tosend) {
    Object[] params = new Object[] { wallet, tosend };
 Object returnValue = invokeExternalContract("6vNF6KMXHqj6UtHgSVYKyf24v4KMRXDC5TzpiMkMUihB", "transfer", params);
 System.out.println(returnValue);
 }
}

Using a similar contract calling the balanceOf function does show success on the monitor. Using the transfer method gives me errors in the contract-executor log which I'll attach to this post.

Caused by: exception.ContractExecutorException: smart contract "6vNF6KMXHqj6UtHgSVYKyf24v4KMRXDC5TzpiMkMUihB" can't be modify
    at com.credits.scapi.v0.SmartContract.invokeExternalContract(SmartContract.java:94)

executor-log-2019-06-12copy.txt

Edit: as the error mentioned that I can not modify the contract, I tried to retrieve the decimal value via the invokeExternalContract function. As the getDecimal() function does not modify the contract. This worked fine.

micmac0 commented 5 years ago

Version 417 The new version seems to behave quite differently but still do not work. Here is an exemple of transaction : https://monitor.credits.com/testnet-r4_2/transaction/79fba823c5480ee5fd9ab65f3987f8ba4743c203b1f37cbeeed2925fc1007ea2.1

I call a business method "addNewBet" and this one call token smartcontract to do a transfer. I got a success status code (with 416 was a failed) on client side but :

and logs I got from one of my node :

16-06-2019 23:58:20.505 [     pool-4-thread-5] DEBUG com.credits.thrift.ContractExecutorHandler - <-- executeByteCode                                                                         
accessId=111                                                                                                                                                                                  
initiatorAddress=Eyh6ZBiM9D9yyLDwFG7nqAwgm8fFfJn7NauZ6bQxsufn                                                                                                                                 invokedContract=SmartContractBinary(contractAddress:EA 9F AD 04 80 14 4D DC AF 12 28 5B C6 57 05 50 FA 77 9D EE ED D5 2A 56 62 90 50 C8 30 8A 1B 66, object:ClassObject(byteCodeObjects:[ByteCodeObject(name:smart.BetMatchTemplate, byteCode:CA FE BA BE 00 00 00 37 01 62 07 00 B3 0A 00 53 00 B4 08 00 91 09 00 4F 00 B5 08 00 B6 09 00 4F 00 B7 08 00 B8 09 00 4F 00 B9 09 00 4F 00 BA 09 00 4F 00 BB 07 00 BC 0A 00 0B 00 B4 09 00 4F 00 BD 09 00 4F 00 BE 0B 00 36 00 BF 09 00 4F 00 C0 09 00 4F 00 C1 09 00 4F 00 C2 0A 00 C3 00 C4 09 00 4F 00 C5 09 00 4F 00 C6 09 00 4F 00 C7 09 00 4F 00 C8 08 00 C9 09 00 4F 00 CA 08 00 CB 09 00...)], instance:AC ED 00 05 73 72 00 16 73 6D 61 72 74 2E 42 65 74 4D 61 74 63 68 54 65 6D 70 6C 61 74 65 B6 17 B3 B0 B4 9C A4 59 02 00 14 4C 00 04 62 65 74 73 74 00 0F 4C 6A 61 76 61 2F 75 74 69 6C 2F 4D 61 70 3B 4C 00 16 63 6F 6D 6D 75 6E 69 74 79 45 73 63 72 6F 77 41 64 64 72 65 73 73 74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2
F 53 74 72 69 6E 67 3B 4C 00 13 63 6F 6D 6D 75 6E 69 74 79 46 65 65 50...), stateCanModify:true)                                                                                             
methodHeaders=[MethodHeader(methodName:addNewBet, params:[<Variant v_int:0>, <Variant v_string:50>])]                                                                                         
executionTime=60000                                                                                                                                                                           version=1                                                                                                                                                                                     
16-06-2019 23:58:20.510 [     pool-4-thread-5] DEBUG com.credits.utils.ContractExecutorServiceUtils - casted param[0] = 0                                                                     16-06-2019 23:58:20.510 [     pool-4-thread-5] DEBUG com.credits.utils.ContractExecutorServiceUtils - casted param[1] = 50                                                                    16-06-2019 23:58:20.510 [     pool-4-thread-5] DEBUG com.credits.utils.StopWatch - isThreadCpuTimeEnabled=true, start measurement 0                                                           
send token to EJmvMuYdZABi8NK7okWP1m273qbqGNeK6wCGc5Bg3X2L, 50                                                                                                                                
16-06-2019 23:58:20.512 [     pool-2-thread-2] DEBUG com.credits.service.node.apiexec.NodeApiExecInteractionServiceImpl - getExternalSmartContractByteCode: ---> accessId = 111; addressBase58
 = Axbxj5oKyDjJg1rtcDNmnxmK36EDHtWA6wQjDDUjxgkF                                                                                                                                               
16-06-2019 23:58:20.513 [     pool-2-thread-2] DEBUG com.credits.service.node.apiexec.NodeApiExecInteractionServiceImpl - getExternalSmartContractByteCode: <--- result = SmartContractGetResu
ltData{byteCodeObjects=[ByteCodeObjectData{name='smart.TokenTBT1', byteCode=[-54, -2, -70, -66, 0, 0, 0, ..............    ............  ...............], stateCanModify=true}
16-06-2019 23:58:20.515 [2op6ES2pc6j2cnTSj261] DEBUG com.credits.utils.ContractExecutorServiceUtils - casted param[0] = EJmvMuYdZABi8NK7okWP1m273qbqGNeK6wCGc5Bg3X2L
16-06-2019 23:58:20.515 [2op6ES2pc6j2cnTSj261] DEBUG com.credits.utils.ContractExecutorServiceUtils - casted param[1] = 50
16-06-2019 23:58:20.515 [2op6ES2pc6j2cnTSj261] DEBUG com.credits.utils.StopWatch - isThreadCpuTimeEnabled=true, start measurement 0
16-06-2019 23:58:20.516 [2op6ES2pc6j2cnTSj261] DEBUG com.credits.utils.StopWatch - stop measurement 0 spentTime=0
result AAAAAAAAAAAAAAAAAA = true
Token transfer ok add bet to 0
init bet to Eyh6ZBiM9D9yyLDwFG7nqAwgm8fFfJn7NauZ6bQxsufn, 50.000000
total bet for Eyh6ZBiM9D9yyLDwFG7nqAwgm8fFfJn7NauZ6bQxsufn 50.000000
16-06-2019 23:58:20.518 [     pool-4-thread-5] DEBUG com.credits.utils.StopWatch - stop measurement 0 spentTime=0
16-06-2019 23:58:20.518 [     pool-4-thread-5] DEBUG com.credits.thrift.ContractExecutorHandler - --> ExecuteByteCodeResult(status:APIResponse(code:0, message:success), results:[SetterMethodResult(status:APIResponse(code:0, message:success), invokedContractState:AC ED 00 05 73 72 00 16 73 6D 61 72 74 2E 42 65 74 4D 61 74 63 68 54 65 6D 70 6C 61 74 65 B6 17 B3 B0 B4 9C A4 59 02 00 14 4C 00 04 62 65 74 73 74 00 0F 4C 6A 61 76 61 2F 75 74 69 6C 2F 4D 61 70 3B 4C 00 16 63 6F 6D 6D 75 6E 69 74 79 45 73 63 72 6F 77 41 64 64 72 65 73 73 74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 4C 00 13 63 6F 6D 6D 75 6E 69 74 79 46 65 65 50..., ret_val:<Variant v_boolean:true>, executionCost:0)], externalContractsState:{})