mhw0 / libethc

Open-source Ethereum C library
https://mhw0.github.io/libethc/
MIT License
46 stars 8 forks source link

rlp: rlp functions produce wrong result when there are too many elements to encode #8

Closed mhw0 closed 11 months ago

DerXanRam commented 11 months ago

Yea... i think so... today i spent all day trying to sign the transaction i mentioned in this issue ... by usng this code

char* SignTnx()
{
char *abi_result = "fda71c7f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000035353535353535353535353535353535353535350000000000000000000000000000000000000000000000000000000014aae8060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7";

    struct eth_rlp rlp0, rlp1;
    struct eth_ecdsa_signature sign;
    uint8_t privkey[] = {0xdf, 0x57, 0x08, 0x9f, 0xeb, 0xba, 0xcf, 0x7b,
                         0xa0, 0xbc, 0x22, 0x7d, 0xaf, 0xbf, 0xfa, 0x9f,
                         0xc0, 0x8a, 0x93, 0xfd, 0xc6, 0x8e, 0x1e, 0x42,
                         0x41, 0x1a, 0x14, 0xef, 0xcf, 0x23, 0x65, 0x6e};

    uint8_t nonce = 0x00, zero = 0x00, keccak[32], *rlp0bytes, *r, *s;
    char *gasprice = "0x04a817c800", *gaslimit = "0x5208", *value = "0x0de0b6b3a7640000";
    char *toaddr = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", *txn;
    uint16_t chainid = 0x1, v;
    size_t rlp0len, rlp1len, siglen = 32;

    ok(eth_rlp_init(&rlp0, ETH_RLP_ENCODE));
    ok(eth_rlp_array(&rlp0));                
    ok(eth_rlp_uint8(&rlp0, &nonce));        
    ok(eth_rlp_hex(&rlp0, &gasprice, NULL)); 
    ok(eth_rlp_hex(&rlp0, &gaslimit, NULL));
    ok(eth_rlp_address(&rlp0, &toaddr));
    ok(eth_rlp_hex(&rlp0, &value, NULL));
    ok(eth_rlp_hex(&rlp0, &abi_result, NULL)); 
    ok(eth_rlp_uint16(&rlp0, &chainid));
    ok(eth_rlp_uint8(&rlp0, &zero)); //   0x,
    ok(eth_rlp_uint8(&rlp0, &zero)); //   0x,
    ok(eth_rlp_array_end(&rlp0));    // ]

    ok(eth_rlp_to_bytes(&rlp0bytes, &rlp0len, &rlp0));
    ok(eth_rlp_free(&rlp0));

    // compute the keccak hash of the encoded rlp elements
    ok(eth_keccak256(keccak, rlp0bytes, rlp0len));
    free(rlp0bytes);

    // sign the transaction
    ok(eth_ecdsa_sign(&sign, privkey, keccak));

    // calculate v
    v = sign.recid + chainid * 2 + 35;
    r = sign.r;
    s = sign.s;

    ok(eth_rlp_init(&rlp1, ETH_RLP_ENCODE));
    ok(eth_rlp_array(&rlp1));
    ok(eth_rlp_uint8(&rlp1, &nonce));
    ok(eth_rlp_hex(&rlp1, &gasprice, NULL));
    ok(eth_rlp_hex(&rlp1, &gaslimit, NULL));
    ok(eth_rlp_address(&rlp1, &toaddr));
    ok(eth_rlp_hex(&rlp1, &value, NULL));
    ok(eth_rlp_hex(&rlp1, &abi_result, NULL)); // replaced
        ok(eth_rlp_uint16(&rlp1, &v));
    ok(eth_rlp_uint8(&rlp1, r));
    ok(eth_rlp_uint8(&rlp1, s));
    ok(eth_rlp_array_end(&rlp1));

    // FIX3: this actually returns the output length
    ok(eth_rlp_to_hex(&txn, &rlp1) > 0);
    ok(eth_rlp_free(&rlp1));
    return txn;
}

the output is 30011482002581ad22808504a817c800825208947a250d5630b4cf539739df2c5dacb4c659f2488d880de0b6b3a7640000b8e4fda71c7f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000035353535353535353535353535353535353535350000000000000000000000000000000000000000000000000000000014aae8060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7 and when i send this to eth_sendRawTransaction RPC the response is {"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"rlp: unknown tx type prefix, got: 48"}}

After doing some research i found that the result from the code is not correct. Like the above rpc error is caused by the transaction signed by the app must be likef845820026a021f62aeb7cf9.................................... should not start by number like the above generated transaction. another problem is {"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"read Nonce: rlp: non-canonical integer format"}} and i think it can be corrected it as u mentioned in this issue but i can not verify it cause the prefix error is appearing first. What do u think bro?

mhw0 commented 11 months ago

Yes, I'm so sorry for your time. Seems like there's a problem with RLP functions. I'll try to fix it.

For now, you can use online services like https://abi.hashex.org and https://toolkit.abdk.consulting/ethereum#rlp It should give the right output.

DerXanRam commented 11 months ago

Yes, I'm so sorry for your time. Seems like there's a problem with ABI functions. I'll try to fix it.

For now, you can use online services like https://abi.hashex.org. It should give the right output.

No problem bro. U contributed this library to c community. We all thank u. There is no working library on the internet that do same thing or close to this. My time is not wasted. i will contribute what i can do to this project. :+1:

mhw0 commented 11 months ago

Hey @DerXanRam. I think I found the issue. Can you please fetch the changes and try again? Also, you should replace the second r and s encode to this:

ok(eth_rlp_bytes(&rlp1, &r, &siglen));
ok(eth_rlp_bytes(&rlp1, &s, &siglen));

Now, the transaction looks valid (https://toolkit.abdk.consulting/ethereum#transaction): Screenshot 2023-08-18 at 22 43 11

DerXanRam commented 11 months ago

ok...let me test it...

DerXanRam commented 11 months ago

Hey @DerXanRam. I think I found the issue. Can you please fetch the changes and try again? Also, you should replace the second r and s encode to this:

ok(eth_rlp_bytes(&rlp1, &r, &siglen));
ok(eth_rlp_bytes(&rlp1, &s, &siglen));

Now, the transaction looks valid (https://toolkit.abdk.consulting/ethereum#transaction): Screenshot 2023-08-18 at 22 43 11

Thanks very much for ur kindness :pray: ... Yeaa it is in correct format..... This is the code. Also i integrated the change from this issue in the code

char *ABIFunction()
{
    struct eth_abi abi;
    char *fn = "swapExactETHForTokens(uint,address[],address,uint)", *hex;
    char *weth = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
    char *usdt = "0xdAC17F958D2ee523a2206206994597C13D831ec7";
    char *to_address = "0x3535353535353535353535353535353535353535";

    uint64_t path_len = 2;
    size_t hexlen;
    uint64_t amount_out_min = 0, deadline = 346744838;
    //////////////////
    eth_abi_init(&abi, ETH_ABI_ENCODE);
    eth_abi_call(&abi, &fn, NULL);
    eth_abi_uint64(&abi, &amount_out_min);
    eth_abi_array(&abi, &path_len); // open an array
    eth_abi_address(&abi, &weth);
    eth_abi_address(&abi, &usdt);
    eth_abi_array_end(&abi); // close the array
    eth_abi_address(&abi, &to_address);
    eth_abi_uint64(&abi, &deadline);
    eth_abi_call_end(&abi);

    ok(eth_abi_to_hex(&abi, &hex, &hexlen));
    ok(eth_abi_free(&abi));
    return hex;
}
char *SignTransaction()
{
    char *abi_result = ABIFunction();

    struct eth_rlp rlp0, rlp1;
    struct eth_ecdsa_signature sign;
    uint8_t privkey[] = {0xdf, 0x57, 0x08, 0x9f, 0xeb, 0xba, 0xcf, 0x7b,
                         0xa0, 0xbc, 0x22, 0x7d, 0xaf, 0xbf, 0xfa, 0x9f,
                         0xc0, 0x8a, 0x93, 0xfd, 0xc6, 0x8e, 0x1e, 0x42,
                         0x41, 0x1a, 0x14, 0xef, 0xcf, 0x23, 0x65, 0x6e};

    uint8_t nonce = 0x00, zero = 0x00, keccak[32], *rlp0bytes, *r, *s;
    char *gasprice = "0x04a817c800", *gaslimit = "0x5208", *value = "0x0de0b6b3a7640000";
    char *toaddr = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", *txn;
    uint16_t chainid = 0x1, v;
    size_t rlp0len, rlp1len, siglen = 32;

    ok(eth_rlp_init(&rlp0, ETH_RLP_ENCODE));
    ok(eth_rlp_array(&rlp0));
    ok(eth_rlp_uint8(&rlp0, &nonce));
    ok(eth_rlp_hex(&rlp0, &gasprice, NULL));
    ok(eth_rlp_hex(&rlp0, &gaslimit, NULL));
    ok(eth_rlp_address(&rlp0, &toaddr));
    ok(eth_rlp_hex(&rlp0, &value, NULL));
    ok(eth_rlp_hex(&rlp0, &abi_result, NULL));
    ok(eth_rlp_uint16(&rlp0, &chainid));
    ok(eth_rlp_uint8(&rlp0, &zero)); //   0x,
    ok(eth_rlp_uint8(&rlp0, &zero)); //   0x,
    ok(eth_rlp_array_end(&rlp0));    // ]

    ok(eth_rlp_to_bytes(&rlp0bytes, &rlp0len, &rlp0));
    ok(eth_rlp_free(&rlp0));

    // compute the keccak hash of the encoded rlp elements
    ok(eth_keccak256(keccak, rlp0bytes, rlp0len));
    free(rlp0bytes);

    // sign the transaction
    ok(eth_ecdsa_sign(&sign, privkey, keccak));

    // calculate v
    v = sign.recid + chainid * 2 + 35;
    r = sign.r;
    s = sign.s;

    ok(eth_rlp_init(&rlp1, ETH_RLP_ENCODE));
    ok(eth_rlp_array(&rlp1));
    ok(eth_rlp_uint8(&rlp1, &nonce));
    ok(eth_rlp_hex(&rlp1, &gasprice, NULL));
    ok(eth_rlp_hex(&rlp1, &gaslimit, NULL));
    ok(eth_rlp_address(&rlp1, &toaddr));
    ok(eth_rlp_hex(&rlp1, &value, NULL));
    ok(eth_rlp_hex(&rlp1, &abi_result, NULL)); // replaced
    ok(eth_rlp_uint16(&rlp1, &v));
    ok(eth_rlp_bytes(&rlp1, &r, &siglen));
    ok(eth_rlp_bytes(&rlp1, &s, &siglen));
    ok(eth_rlp_array_end(&rlp1));

    // FIX3: this actually returns the output length
    ok(eth_rlp_to_hex(&txn, &rlp1) > 0);
    ok(eth_rlp_free(&rlp1));
    return txn;
}

Where did u convert your private key to hex? or did u convert it manually? The final step i left is filling the correct private key and sign real transaction thanks to u.

DerXanRam commented 11 months ago

Does online converters trust worthy ?

mhw0 commented 11 months ago

Thanks very much for ur kindness 🙏 ... Yeaa it is in correct format..... This is the code. Also i integrated the change from this https://github.com/mhw0/libethc/issues/6 in the code

You're welcome. For contract calls, value should be zero, but, it's 0x0de0b6b3a7640000 in your code. So, first and second values are:

ok(eth_rlp_uint8(&rlp0, &zero));
// ...
ok(eth_rlp_uint8(&rlp1, &zero));

Where did u convert your private key to hex? or did u convert it manually? The final step i left is filling the correct private key and sign real transaction thanks to u.

I actually had private key in hex format, and converted it manually. If you're lazy, there's a function called eth_hex_to_bytes :)

Does online converters trust worthy ?

Hex to bytes, bytes to hex? I wouldn't trust.

If you have any questions, feel free to ask.

Closing the issue. Fixed in bb74550e73f151baea649d818e482e87db10e7df