Skip to content

Commit

Permalink
feat: add bignumber abi decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
as-iotex authored and as-iotex committed Apr 17, 2022
1 parent f21aedd commit 59d22f1
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 2 deletions.
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ add_library(iotex-client STATIC
src/extern/crypto/ed25519-donna/ed25519.c
# CppLogger
src/extern/cpplogger/cpplogger.cpp
# Bignum
src/extern/uint256_t/uint256_t.cpp
src/extern/uint256_t/uint128_t/uint128_t.cpp

# Protobuf
src/protobuf_files/c_files/action.pb.c
Expand All @@ -65,6 +68,7 @@ add_library(iotex-client STATIC
src/abi/abiDecode.cpp
src/helpers/json_helper.cpp
src/helpers/client_helper.cpp
src/bignum/bignum.cpp
src/contract/contract.cpp
src/contract/xrc20Contract.cpp
)
Expand All @@ -78,7 +82,8 @@ target_include_directories(iotex-client
PRIVATE src/protobuf_files/c_files
PRIVATE src/extern/crypto # Needed for sources inside crypto
PRIVATE src/extern/nanopb
PUBLIC src/extern
PUBLIC src/extern/uint256_t/uint128_t/ # Needed for sources inside uint256_t
PUBLIC src/extern
)

target_compile_definitions(iotex-client
Expand Down
22 changes: 22 additions & 0 deletions src/abi/abiDecode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using namespace iotex;
using namespace std;
using namespace iotex::abi;
using namespace iotex::bignum;

namespace
{
Expand Down Expand Up @@ -43,6 +44,27 @@ uint64_t iotex::abi::decode::decodeUint64(const char pData[64])
return out;
}

ResultCode iotex::abi::decode::decodeBigUint(const char* pData, size_t uintSize, iotex::bignum::Bignum& out)
{
if (uintSize == 0 || uintSize % 8 || uintSize > 256)
{
return ResultCode::ERROR_BAD_PARAMETER;
}

uint8_t bytesSize = uintSize/8;
uint8_t paddingBytes = 32 - bytesSize;
pData += paddingBytes*2;

// Copy to a new buffer so we can zero terminate it and pass the string to the bignum constructor.
char zeroTerminated[bytesSize*2 + 1];
zeroTerminated[bytesSize*2] = '\0';
memcpy(zeroTerminated, pData, bytesSize*2);

out = Bignum(zeroTerminated, NumericBase::Base16);

return ResultCode::SUCCESS;
}

int8_t iotex::abi::decode::decodeInt8(const char pData[64])
{
int64_t out = 0;
Expand Down
10 changes: 10 additions & 0 deletions src/abi/abiDecode.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef IOTEX_ABI_DECODE_H
#define IOTEX_ABI_DECODE_H

#include "bignum/bignum.h"
#include "helpers/client_helper.h"
#include "IoTeXConstants.h"
#include "IoTeXResultCodes.h"
Expand Down Expand Up @@ -55,6 +56,15 @@ uint32_t decodeUint32(const char pData[64]);
*/
uint64_t decodeUint64(const char pData[64]);

/**
* @brief Decodes an ABI encoded big unsigned integer (up to 256 bit).
*
* @param pData The ABI encoded data.
* @param uintSize The size of the integer in bits.
* @param[out] out The decoded integer.
*/
iotex::ResultCode decodeBigUint(const char* pData, size_t uintSize, iotex::bignum::Bignum& out);

/**
* @brief Decodes an ABI encoded 8 bit signed integer.
*
Expand Down
35 changes: 35 additions & 0 deletions src/bignum/bignum.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "bignum/bignum.h"

using namespace iotex::bignum;

Bignum::Bignum()
{
_u256 = uint256_0;
}

Bignum::Bignum(const char* str, NumericBase base)
{
uint8_t baseInt = 16;
if (base == NumericBase::Base10) { baseInt = 10; }

_u256 = uint256_t(str, baseInt);
}

IotexString Bignum::ToString(NumericBase base) const
{
if (base == NumericBase::Base10)
{
return _u256.str(10);
}
else if (base == NumericBase::Base16)
{
return _u256.str(16);
}
else return "";
}

Bignum& Bignum::operator=(const Bignum& bignum)
{
_u256 = uint256_t(bignum.ToString(NumericBase::Base16), 16);
return *this;
}
49 changes: 49 additions & 0 deletions src/bignum/bignum.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once

#include "extern/uint256_t/uint256_t.h"
#include "helpers/client_helper.h"

namespace iotex
{
namespace bignum
{
enum NumericBase
{
Base10,
Base16
};

/**
* @brief Represents an unigned integer of up to 256 bytes.
*
*/
class Bignum
{
public:
/**
* @brief Default constructor. Constructs a Bignum with the value of 0.
*/
Bignum();

/**
* @brief Constructs a Bignum from a string value.
*
* @param str The value.
* @param base The numeric base of the string (Decimal or Hexadecimal).
*/
Bignum(const char* str, NumericBase base);

/**
* @brief Returns the value as a string.
*
* @param base The numeric base to use (Decimal or Hexadecimal).
*/
IotexString ToString(NumericBase base) const;

Bignum& operator=(const Bignum& bignum);

private:
uint256_t _u256;
};
} // namespace bignum
} // namespace iotex
24 changes: 23 additions & 1 deletion tests/src/abi/decode/abiDecodeUintTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
#include "abi/abiDecode.h"
#include "contract/contract.h"
#include "signer/signer.h"
#include "bignum/bignum.h"

using namespace std;
using namespace testing;
using namespace iotex;
using namespace iotex::abi::decode;
using namespace iotex::bignum;

class AbiDecodeUintTests : public Test
{
Expand Down Expand Up @@ -109,4 +111,24 @@ TEST_F(AbiDecodeUintTests, Handles0xPrefix)
ResultCode result = decodeUint<1>(encoded, strlen(encoded), &decoded);
ASSERT_EQ(ResultCode::SUCCESS, result);
ASSERT_EQ(29, decoded);
}
}

TEST_F(AbiDecodeUintTests, Bignum_Ok)
{
const char expectedDecimal[] = "446371678961165142885801714189622662489706559239886995455";
char encoded[] = "0000000000000000123456789acbdeffffffffffffffffffffffffffffffffff";

Bignum decoded;

// Decode as uint64
ResultCode result = decodeBigUint(encoded, 256, decoded);
ASSERT_EQ(ResultCode::SUCCESS, result);
auto decodedStr = decoded.ToString(NumericBase::Base10).c_str();
ASSERT_STREQ(expectedDecimal, decodedStr);

// Decode as 24 bytes. This tests it handles the padding bytes correctly.
result = decodeBigUint(encoded, 192, decoded);
ASSERT_EQ(ResultCode::SUCCESS, result);
decodedStr = decoded.ToString(NumericBase::Base10).c_str();
ASSERT_STREQ(expectedDecimal, decodedStr);
}

0 comments on commit 59d22f1

Please sign in to comment.