Implementation of the Variable length integer in C

0

Anyone can give me a idea of how implement in C this concept of Variable length integer which encoded the numer of transactions in a block? based on what is described here, I think is something lime that:

if(value=?)
    uint8_t number_transactions = length;
else if(value=?)
    uint16_t number_transactions = 0xFD+length;
else if(value=?)
    uint32_t number_transactions = 0xFE_length;
else
    uint64_t number_transactions = 0xFF_length;

where number_transactions would be the value concatenated on the block. But how implement this? This code does the same described in the bitcoin wiki?

UPDATE

char* varint(unsigned long size) {
  char* number;
  if(size < 252) {
    number = malloc(1);
    number[0] = (uint8_t)size;
  } else if(size>=253 && size<65535) {
    number = malloc(3);
    number[0] = 0xfd;
    memcpy(&number[1], (uint16_t)&size, sizeof(uint16_t));
  } else if(size>=65536 && size<4294967295) {
    number = malloc(5);
    number[0] = 0xfe;
    memcpy(&number[1], (uint32_t)&size, sizeof(uint32_t));
  } else if(size>=4294967296) {
    number = malloc(9);
    number[0] = 0xff;
    memcpy(&number[1], (uint64_t)&size, sizeof(uint64_t));
  }
  return NULL;
}

message from compiler:

bitcoin_rpc.c: In function ‘varint’:
bitcoin_rpc.c:230:24: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     memcpy(&number[1], (uint16_t)&size, sizeof(uint16_t));
                        ^
bitcoin_rpc.c:230:24: warning: passing argument 2 of ‘memcpy’ makes pointer from integer without a cast [-Wint-conversion]
In file included from bitcoin_rpc.c:4:0:
/usr/include/string.h:42:14: note: expected ‘const void * restrict’ but argument is of type ‘short unsigned int’
 extern void *memcpy (void *__restrict __dest, const void *__restrict __src,
              ^~~~~~
bitcoin_rpc.c:234:24: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     memcpy(&number[1], (uint32_t)&size, sizeof(uint32_t));
                        ^
bitcoin_rpc.c:234:24: warning: passing argument 2 of ‘memcpy’ makes pointer from integer without a cast [-Wint-conversion]
In file included from bitcoin_rpc.c:4:0:
/usr/include/string.h:42:14: note: expected ‘const void * restrict’ but argument is of type ‘unsigned int’
 extern void *memcpy (void *__restrict __dest, const void *__restrict __src,
              ^~~~~~
bitcoin_rpc.c:238:24: warning: passing argument 2 of ‘memcpy’ makes pointer from integer without a cast [-Wint-conversion]
     memcpy(&number[1], (uint64_t)&size, sizeof(uint64_t));
                        ^
In file included from bitcoin_rpc.c:4:0:
/usr/include/string.h:42:14: note: expected ‘const void * restrict’ but argument is of type ‘long unsigned int’
 extern void *memcpy (void *__restrict __dest, const void *__restrict __src,

Kleber Mota

Posted 2017-08-28T00:30:59.587

Reputation: 131

Answers

1

No. The compact size unsigned integers are not uints (except for the base one of one byte). They are a serialization, so it is actually just an array of bytes. You just compare the number you are serializing to the boundaries and determine from there what the prefix byte is. Bitcoin.org does a better job of describing this: https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers. Note that you will need to understand hex numbers are and how they work in C.

Andrew Chow

Posted 2017-08-28T00:30:59.587

Reputation: 40 910

I implement a version of this method based on your sugestion, could you check if it's works? Also, there is some compiler warnings; do you have any sugestion of how to solve them?Kleber Mota 2017-08-28T02:36:24.570

1You are casting pointers to uints. Don't do that since you are changing the pointer type, not the number type. Instead you should cast the variable first, then get a pointer to it or cast to a type pointer (e.g. uint32_t*)Andrew Chow 2017-08-28T03:23:44.823

0

Here is libblkmaker's implementation:

static
char varintEncode(unsigned char *out, uint64_t n) {
    if (n < 0xfd)
    {
        out[0] = n;
        return 1;
    }
    char L;
    if (n <= 0xffff)
    {
        out[0] = '\xfd';
        L = 3;
    }
    else
    if (n <= 0xffffffff)
    {
        out[0] = '\xfe';
        L = 5;
    }
    else
    {
        out[0] = '\xff';
        L = 9;
    }
    for (unsigned char i = 1; i < L; ++i)
        out[i] = (n >> ((i - 1) * 8)) % 256;
    return L;
}

Geremia

Posted 2017-08-28T00:30:59.587

Reputation: 3 665