16 days ago

在比特币中生成地址是免费的,一个人可以生成多个地址,每生成一个地址就代表着生成了对应的一个私钥和一个公钥,地址和公钥是可以公开给别人看的,但私钥必须隐藏好,否则你很可能会失去这个地址内所有的比特币。

//首先调用函数仓库,函数仓库分为三种:1、操作系统的函数仓库;2、标准函数仓库;3、第三方机构或个人写的函数仓库。
其中,stdio.h(标准输出和输入的函数库)、stdlib.h(内存分配的函数库)和 string.h(字符串和内存管理函数库)都是三个标准且常用的函数仓库。
tomcrypt.h是第三方机构函数库,#define TFM_DESE是为了激活tomcrypt.h内的函数用的,是调用此函数的标准写法。

#define TFM_DESC

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "tomcrypt.h"
#include "tfm.h"

//这里是定义base58check encoding的用法,目的是将生字节转换成base58字符串。
因为在直接调用这个函数方法时失败,所以将源代码粘贴到这里,所以代码看起来很长。

static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijk$

// Base58

int b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
{
   const uint8_t *bin = data;
   int carry;
   ssize_t i, j, high, zcount = 0;
   size_t size;

   while (zcount < binsz && !bin[zcount])
      ++zcount;

   size = (binsz - zcount) * 138 / 100 + 1;
   uint8_t buf[size];
   memset(buf, 0, size);

   for (i = zcount, high = size - 1; i < binsz; ++i, high = j)
   {
      for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
      {
         carry += 256 * buf[j];
         buf[j] = carry % 58;
         carry /= 58;
      }
   }
   
     for (j = 0; j < size && !buf[j]; ++j);

   if (*b58sz <= zcount + size - j)
   {
      *b58sz = zcount + size - j + 1;
      return 0;
   }

   if (zcount)
      memset(b58, '1', zcount);
   for (i = zcount; j < size; ++i, ++j)
      b58[i] = b58digits_ordered[buf[j]];
   b58[i] = '\0';
   *b58sz = i + 1;

   return 1;
}

//这里是为了调用随机数生成器
char *get_random(int length)
{
   FILE *_8425;
   char *random;

   random = malloc(length);

   _8425 = fopen("/dev/urandom", "r");
   fread(random, 1, length, _8425);

   return random;
}

//这里是为了获得私钥,并输出私钥
char *get_private(int *length)
{
   prng_state _2761;
   ecc_key _5440;
   char *private;

   private = malloc(*length = 1000);
   
   //这是调用了 ECC 加密学函数,为了生成私钥
   ecc_make_key(&_2761, find_prng("sprng"), 32, &_5440);
   
   //这个函数是为了以字符串的形式输出私钥
   ecc_export(private, length, PK_PRIVATE, &_5440);
   
    return private;
}

//这里是为了引入私钥,生成并输出公钥
char *get_public(int *length, char *private)
{
   ecc_key _1006;
   char *public;

   //这里引入了私钥
   ecc_import(private, *length, &_1006);
   public = malloc(*length = 1000);
   
   //这里生成了公钥,并以字符串的形式输出
   ecc_export(public, length, PK_PUBLIC, &_1006);

   return public;
}

//这里是主函数,上面的函数都会在这个主函数中被调用
int main(int _3464, char **_1019, char **_1109)
{
   int _7727, _6282, _6904, _9440;
   char *private, *public, *new_private, *new_public;
   prng_state _3618;

   //这三行是配合tomcrypt.h这个函数库的,是调用这个函数的标准写法。
   ltc_mp = tfm_desc;
   register_prng(&sprng_desc);
   register_hash(&sha256_desc);
  
   //以下是生成地址的流程,请结合流程图来看代码
   private = get_private(&_7727);
   _6282 = _7727;
   public = get_public(&_6282, private);

   new_private = malloc(_6904 = 1000);
   new_public = malloc(_9440 = 1000);

   //base64 是将字符串转换成生字节
   base64_encode(private, _7727, new_private, &_6904);
   base64_encode(public, _6282, new_public, &_9440);

   new_private[_6904] = 0;
   new_public[_9440] = 0;
   
   //以字符串的形式打印私钥
   printf("private: %s%c", new_private, 10);
   
   //以字符串的形式打印公钥
   printf("public: %s%c", new_public, 10);

   hash_state _8438; char *_6643;

   //sha256
   _6643 = malloc(32);
   sha256_init(&_8438);
   sha256_process(&_8438, public, _6282);
   sha256_done(&_8438, _6643);

   hash_state _7516; char *_4485;
   
   //ripemd160
   _4485 = malloc(21);
   _4485[0] = 137;
   rmd160_init(&_7516);
   rmd160_process(&_7516, _6643, 32);
   rmd160_done(&_7516, _4485 + 1);
   
   hash_state _5545; char *_2796;

   //sha256
   _2796 = malloc(32);
   sha256_init(&_5545);
   sha256_process(&_5545, _4485, 21);
   sha256_done(&_5545, _2796);

   hash_state _7512; char *_2952;

   //sha256
   _2952 = malloc(32);
   sha256_init(&_7512);
   sha256_process(&_7512, _2796, 32);
   sha256_done(&_7512, _2952);

   char *_1230;

   _1230 = malloc(25);
   memcpy(_1230, _4485, 21);
   memcpy(_1230 + 21, _2952, 4);
   
   char *_7665; int _9583;

   //base58 将生字节转换成字符串
   _7665 = malloc(_9583 = 100);
   b58enc(_7665, &_9583, _1230, 25);
   _7665[_9583] = 0;
   
   //以字符串的形式打印地址
   printf("address: %s%c", _7665, 10);
}

登陆服务器,然后 cd /tmp/relay
cp * /home/yourname (你的名字拼音) 【这一步是将代码全部复制到你私人的服务器上,请在你自己的服务器上测试】
cd
使用 nano 来打开文件
退出 nano 编辑器:contrl + x
比如:nano generate.c
将 generate.c 转换成执行文件的基本框架:
第一步,编译:tcc -c -o generate.o generate.c (generate.o 文件生成)
第二步,连接:tcc -o generate generate.o (generate 执行文件生成,并且名字是可以自定义的)

这两步老师都生成好了,不需要再操作,如果想操作可以这样做:
mkdir xcy 新建一个名叫 xcy 的文件夹
cp libtomcrypt.a libtfm.a generate.c xcy
cd xcy
tcc -c -o generate.o generate.c
tcc -o generate generate.o libtomcrypt.a libtfm.a (后面两个是加密算法的文件,在 generate 中调用了很多加密函数都是来自于这两个文件,我们要将这两个文件跟 generate 连接起来。)
执行文件:./generate

 
4 months ago

table_create这个函数在内存中的图形展示:

//创造table
char *table_create(int limit)
{
   char *A;
   int *B;

   A = malloc(16 * limit + 8);
   B = (int *) A;
   *B = 0;
   B = (int *) (A + 4);
   *B = limit;

   return A;
}

//将其他节点信息逐一增加到这个table中
int table_add(char *table, int address, int port, int recent, int expectation)
{
   int *A, *B, *C, *D, *E, *F;

   A = (int *) table;
   B = (int *) (table + 4);
   C = (int *) (table + 8 + *A * 16);
   D = (int *) (table + 8 + *A * 16 + 4);
   E = (int *) (table + 8 + *A * 16 + 8);
   F = (int *) (table + 8 + *A * 16 + 12);

   *C = address;
   *D = port;
   *E = recent;
   *F = expectation;
   
   *A = *A + 1;

   return 1;
}

//获取table的row,得到每一行的IP地址和端口,即其他节点的身份号
int table_get_row(char *table, int sequence, int *address, int *port)
{
   int *A, *B, *C, *D;

   A = (int *) table;
   B = (int *) (table + 4);

   if (sequence >= *A)
      return 0;

   C = (int *) (table + 8 + 16 * sequence);
   D = (int *) (table + 8 + 16 * sequence + 4);

   *address = *C;
   *port = *D;

   return 1;
}

//获取已经有几个节点在维持中
int table_get_attainment(char *table)
{
   int *B;
   B = (int *) table;
   
   return *B;
}

//获取这片内存能最多能维持几个节点
int table_get_limit(char *table)
{
   int *B;
   B = (int *) (table + 4);

   return *B;
}

 
4 months ago
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "sys/socket.h" //套接字函数库
#include "arpa/inet.h"  //网络协议套接字函数库

//读文件的函数
char *read_file(char *path, int *length) {

   FILE *file;
   char *contents;

   file = fopen(path, "r+");
   fseek(file, 0, SEEK_END);
   *length = ftell(file);
   fseek(file, 0, SEEK_SET);

   contents = malloc(*length);
   fread(contents, 1, *length, file);
   fclose(file);
   
   return contents;
}

//建立监听者套接字
int establish(int port)
{
   int listener;
   struct sockaddr_in address;

   address.sin_family = 2;
   address.sin_port = htons(port);
   address.sin_addr.s_addr = inet_addr("0.0.0.0");

   if ((listener = socket(2, 1, 0)) == -1)
      exit(116);

   if (bind(listener, (struct sockaddr *) &address, sizeof (address)) == -1)
      exit(148);

   if (listen(listener, 1024) == -1)
      exit(75);
      
   return listener;
}

//主代码
int main(int count, char **arguments) {

   char *content;
   int acceptor, listener, size;

//参数不能少于三个,否则退出
   if (count < 3)
      exit(21);

//读取第二个参数,即文件内容
   content = read_file(arguments[1], &size);
   
//第三个参数为监听端口,开始监听   
   listener = establish(atoi(arguments[2]));

   while (1) {

      struct sockaddr_in _7231;
      int _8352 = 16;
      char *_9710;
      
//accpet是一个系统呼叫,每一次新的连接被建立都会运行accept,有三个参数,第一个为监听者的端口,第二个和第三个为option(选填),在这里为了接受连接者的IP地址,第二个参数放入了一个指向连接者IP地址的指针,第三个参数就是这个IP地址的长度      
      acceptor = accept(listener, (struct sockaddr *) &_7231, &_8352);
      _9710 = (char *) &(_7231.sin_addr.s_addr);//将IP地址转换成四个字节的通用IP地址的格式

printf("%hhu.%hhu.%hhu.%hhu%c", _9710[0], _9710[1], _9710[2], _9710[3], 10);//打印IP地址
printf("a connection has occurred (%d)%c", time(0), 10);

//这是HTTP信息包头部,设置好了状态码(200),然后连接一次性还是连续性(这里是一次性),然后是内容长短和内容类型,然后将content(这个文件)复制到最后面
      char *_2783 = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: %d$
      char *_2279 = malloc(10000);
      sprintf(_2279, _2783, size);
      char *_8931 = malloc(size + strlen(_2279));
      memcpy(_8931, _2279, strlen(_2279));
      memcpy(_8931 + strlen(_2279), content, size);
      
//发送将整个信息发送给连接者,只需要在某个浏览器输入监听者的IP地址和监听端口,就可以看到这个content文件内容     
      send(acceptor, _8931, strlen(_2279) + size, 0);
//因为是循环,所以要释放内存
      free(_8931);
   }
}

信息补充,监听者流程:

 
4 months ago

限制状态机:在某个状态下就会产生某种行为,然后到下一个状态。
写限制状态机的基本逻辑:
分配一个内存
造一推指针
给每一个指针赋值
返回这片内存

//得到编码
short get_2518(char *state)
{
   short *_4053;

   _4053 = (short *) state;

   return *_4053;
}

//得到传输接口的状态(0/1)
char get_1385(char *state)
{
   char *_1330;

   _1330 = (char *) (state + 2);

   return *_1330;
}

//得到端口的前半部分
char get_2321(char *state)
{
   char *_7402;

   _7402 = (char *) (state + 3);

   return *_7402;
}

//得到端口的后半部分
char get_3818(char *state)
{
   char *_9253;

   _9253 = (char *) (state + 4);

   return *_9253;
}

//状态编码为5860的状态函数,在这个状态下,会执行的动作
char *create_9473(char _8928, char _5979, char _1702)
{
   char *_8525, *_8068, *_1882, *_4854;
   short *_4034;

   _8525 = malloc(5);

   _4034 = (short *) _8525;
   _8068 = (char *) (_8525 + 2);
   _1882 = (char *) (_8525 + 3);
   _4854 = (char *) (_8525 + 4);

   *_4034 = 5860;
   *_8068 = _8928;
   *_1882 = _5979;
   *_4854 = _1702;

   return _8525;
}

//状态编码为9029的状态函数,在这个状态下,会执行的动作
char *create_5603()
{
   char *_5714;
   short *_5028;

   _5714 = malloc(2);

   _5028 = (short *) _5714;

   *_5028 = 9029;

   return _5714;
}

//状态编码为6804的状态函数,在这个状态下,会执行的动作
char *create_4351()
{
   char *_1516;
   short *_4883;

   _1516 = malloc(2);

   _4883 = (short *) _1516;

   *_4883 = 6804;

   return _1516;
}

//状态编码为6254的状态函数,在这个状态下,会执行的动作
char *create_9159(char _1968, char _9353)
{
   char *_1568, *_3720, *_6614;
   short *_5647;

   _1568 = malloc(4);

   _5647 = (short *) _1568;
   _3720 = (char *) (_1568 + 2);
   _6614 = (char *) (_1568 + 3);

   *_5647 = 6254;
   *_3720 = _1968;
   *_6614 = _9353;

   return _1568;
}

//信息传输,参数:状态,字节,与连接者通讯的套接字【对方端口】(请看最下面的一张图,accept会产生一个新的套接字来与连接者通讯)
char *transit(char *state, char byte, int other) 
{
   printf("transit has been entered%c", 10);

//当状态为9029并且字节为59时,跳到5860这个状态,参考create_9473这个状态创造函数。
   if (get_2518(state) == 9029 && byte == 59) {

      printf("state is %d%c", 9029, 10);

      return create_9473(0, 0, 0);//参数为0,为初始状态
   }

//当状态为9029时,跳到6804这个状态,参考create_4351这个状态创造函数。(6804这个状态没有动作)
   if (get_2518(state) == 9029) {

      printf("state is %d%c", 9029, 10);

      return create_4351();
   }

//当状态为5860且传输进度为0时(初始化状态是0),跳到传输进度为1的状态下,调用create_9473这个状态创造函数。
   if (get_2518(state) == 5860 && get_1385(state) == 0) {

      printf("state is %d, progress is %d%c", 5860, 0, 10);

      return create_9473(1, byte, 0);//获得端口的前半部分
   }

//当状态为5860且传输状态为1时,跳到6254这个状态,调用create_9159这个状态创造函数,获得一个4字节的内存指针,2个字节放6254这个编码,一个字节放端口的前半部分,一个字节放端口的后半部分。
   if (get_2518(state) == 5860 && get_1385(state) == 1) {

      printf("state is %d, progress is %d%c", 5860, 1, 10);

      return create_9159(get_2321(state), get_3818(state));//获得端口的后半部分
   }
}

void handle(char *conservation, char *private, int self)
{
   struct sockaddr_in _7231;
   int _8352 = 16;
   char _3049, *state;
   int other, _6888;
      char *_9710;

   while (1) {

      other = accept(self, (struct sockaddr *) &_7231, &_8352);
      _9710 = (char *) &(_7231.sin_addr.s_addr);
      state = create_5603();

printf("new connection: %hhu.%hhu.%hhu.%hhu%c", _9710[0], _9710[1], _9710[2], _9710[3], 10);

      while (1) {

         _6888 = recv(other, &_3049, 1, 0);

         if (_6888 == -1 || _6888 == 0) {

            printf("conection broken%c", 10);
            break;
         }

         state = transit(state, _3049, other);
      }
   }
}

信息补充,以下是监听者的流程,帮助你了解每个函数的作用:

 
5 months ago

1、我们需要指定储存卷宗(文件夹)
2、我们需要指定端口
3、指定别的节点的地址和端口
4、指定创世区块的摘要(每个区块的merkle tree)

存储区块的方式:


指向区块内容的指针:可以理解成图书馆中某一本书存放在书架上的具体位置。

没有注释的地方请看上一篇如何写创世区块的代码

#define TFM_DESC

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "sys/socket.h" //这个是套接字的函数库
#include "arpa/inet.h"//这个是专门面对互联网的套接字函数库
#include "tfm.h"
#include "tomcrypt.h"

char *get_rmd160(char *buffer, int size)
{
   hash_state resource;
   char *digest;

   digest = malloc(20);
   rmd160_init(&resource);
   rmd160_process(&resource, buffer, size);
   rmd160_done(&resource, digest);

   return digest;
}

char *get_sha256(char *buffer, int size)
{
   hash_state resource;
   char *digest;

   digest = malloc(32);
   sha256_init(&resource);
   sha256_process(&resource, buffer, size);
   sha256_done(&resource, digest);

   return digest;
}

static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

// Thanks to Luke Dashjr.

int b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
{
   const uint8_t *bin = data;
   int carry;
   ssize_t i, j, high, zcount = 0;
   size_t size;
   
   while (zcount < binsz && !bin[zcount])
      ++zcount;
   
   size = (binsz - zcount) * 138 / 100 + 1;
   uint8_t buf[size];
   memset(buf, 0, size);
   
   for (i = zcount, high = size - 1; i < binsz; ++i, high = j)
   {
      for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
      {
         carry += 256 * buf[j];
         buf[j] = carry % 58;
         carry /= 58;
      }
   }
   
   for (j = 0; j < size && !buf[j]; ++j);
   
   if (*b58sz <= zcount + size - j)
   {
      *b58sz = zcount + size - j + 1;
      return 0;
   }
   
   if (zcount)
      memset(b58, '1', zcount);
   for (i = zcount; j < size; ++i, ++j)
      b58[i] = b58digits_ordered[buf[j]];
   b58[i] = '\0';
   *b58sz = i + 1;
   
   return 1;
}

int scan(char *source)
{
   int *size;

   size = (int *) source;

   return *size;
}

unsigned char *get_private(unsigned int *length)
{
   prng_state random;
   ecc_key key;
   unsigned char *buffer;

   buffer = malloc(*length = 1000);
   ecc_make_key(&random, find_prng("sprng"), 32, &key);
   ecc_export(buffer, length, PK_PRIVATE, &key);

   return buffer;
}

unsigned char *get_public(unsigned int *length, unsigned char *private)
{
   ecc_key key;
   unsigned char *buffer;

   ecc_import(private, *length, &key);
   buffer = malloc(*length = 1000);
   ecc_export(buffer, length, PK_PUBLIC, &key);

   return buffer;
}

char *read_file(char *path, int *length) {

   FILE *file;
   char *contents;

   file = fopen(path, "r+");
   fseek(file, 0, SEEK_END);
   *length = ftell(file);
   fseek(file, 0, SEEK_SET);

   contents = malloc(*length + 1);
   fread(contents, 1, *length, file);
   fclose(file);

   return contents;
}

//void是返回空值,即没有返回值。否则需返回0或者1表示失败或者成功
void write_file(char *path, char *substance, int length)
{
   FILE *file;

   file = fopen(path, "w");
   fwrite(substance, 1, length, file);
   fclose(file);
}

char *string_create(char *old, int length)
{
   char *new;
   int *_6157;

   new = malloc(length + 4) + 4;
   memcpy(new, old, length);

   _6157 = (int *) (new - 4);
   *_6157 = length;

   return new;
}

char *string_create_improper(char *old)
{
   char *new;
   int *_7193;

   new = malloc(strlen(old) + 4) + 4;
   memcpy(new, old, strlen(old));

   _7193 = (int *) (new - 4);
   *_7193 = strlen(old);

   return new;
}

int string_measure(char *buffer)
{
   int *_4721;

   _4721 = (int *) (buffer - 4);

   return *_4721;
}

uint8_t *create_input(uint32_t index, uint8_t *public, uint8_t *signature, uint8_t *transaction)
{
   uint8_t *result;
   uint32_t a, b, c;

   result = malloc(48 + string_measure(public) + string_measure(signature));

   a = 48 + string_measure(public) + string_measure(signature);
   b = string_measure(public);
   c = string_measure(signature);

   memcpy(result, &a, 4);
   memcpy(result + 4, &index, 4);
   memcpy(result + 8, &b, 4);
   memcpy(result + 12, public, b);
   memcpy(result + 12 + b, &c, 4);
   memcpy(result + 16 + b, signature, c);
   memcpy(result + 16 + b + c, transaction, 32);
   return result;
}

uint8_t *create_output(uint8_t *address, uint64_t amount)
{
   uint8_t *result;
   uint32_t a, b;

   result = malloc(16 + string_measure(address));

   a = 16 + string_measure(address);
   b = string_measure(address);

   memcpy(result, &a, 4);
   memcpy(result + 4, &b, 4);
   memcpy(result + 8, address, b);
   memcpy(result + 8 + b, &amount, 8);

   return result;
}

uint8_t *create_head(uint8_t *current, uint32_t nonce, uint8_t *previous, uint8_t *target, uint32_t time, uint32_t valence)
{
   uint8_t *result;

   result = malloc(108);

   memcpy(result, current, 32);
   memcpy(result + 32, &nonce, 4); 
   memcpy(result + 36, previous, 32);
   memcpy(result + 68, target, 32);
   memcpy(result + 100, &time, 4);
   memcpy(result + 104, &valence, 4);

   return result;
}

//创建一个新的能放limit个区块的容量
char *storage_create(int limit)
{
   char *A;
   int *B;

   A = malloc(40 * limit + 8);
   B = (int *) A;
   *B = 0;
   B = (int *) (A + 4);
   *B = limit;

   return A;
}

//得到容量值
int storage_get_limit(char *storage)
{
   int *B;
   B = (int *) (storage + 4);

   return *B;
}

//得到实际存放的区块数量
int storage_get_attainment(char *storage)
{
   int *B;
   B = (int *) storage;

   return *B;
}

//通过遍历配对的方式找到需要的那个指向区块内容的指针
char *storage_search(char *storage, char *target)
{
   int *A, X;
   char *B, **C, *digest;

   A = (int *) storage;
   X = 0;

   while (X < *A) {

      B = (char *) (storage + 8 + X * 40);//如果X为0则从第一个区块开始与目标区块相比较
      C = (char **) (storage + 8 + X * 40 + 36); //将内存中的指针移动到(指向区块内容的指针)的位置

   digest = B;
   printf("comparing: %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%c", digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15], digest[16], digest[17], digest[18], digest[19], digest[20], digest[21], digest[22], digest[23], digest[24], digest[25], digest[26], digest[27], digest[28], digest[29], digest[30], digest[31], 10);
   digest = target;
   printf("against: %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%c", digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15], digest[16], digest[17], digest[18], digest[19], digest[20], digest[21], digest[22], digest[23], digest[24], digest[25], digest[26], digest[27], digest[28], digest[29], digest[30], digest[31], 10);

      if (memcmp(B, target, 32) == 0) { //从指针B的的第一个字节开始与指针target的第一个字节开始比较,直到第32个字节完全相等,那么表示找到我们需要的目标区块了
         printf("found%c", 10);
         return *C;//返回指向目标区块内容的指针
      }

      X++;
   }

   return 0;
}

//在storage中依次增加区块,根据图片来理解
int storage_add(char *storage, char *digest, int length, char *substance)
{
   int *A, *B, *D;
   char *C, **E;

   A = (int *) storage;
   B = (int *) (storage + 4);

   if (*A == *B)//当存放的区块达到最高容量时,则存储失败
      return 0;

   C = (char *) (storage + 8 + *A * 40);//依次存放区块
   D = (int *) (C + 32);//在摘要的后面存放区块的大小
   E = (char **) (C + 32 + 4);//在区块大小的后面存放(指向区块内容的指针)

   memcpy(C, digest, 32);//将摘要放在区块最开始的位置
   *D = length;
   *E = substance;
   *A = *A + 1;//随着区块依次存放,实际存放的数量则会依次加1

   return 1;//返回1表示成功
}

//每一个节点都会维持住一个Table(关系型数据库是以Table的方式来存储数据的),所以我们需要构建一个有IP地址、端口、最新通讯和指望通讯的Table。
char *table_create(int limit)
{
   char *A;
   int *B;

   A = malloc(16 * limit + 8);
   B = (int *) A;
   *B = 0;
   B = (int *) (A + 4);
   *B = limit;

   return A;
}

int table_add(char *table, int address, int port, int recent, int expectation)
{
   int *A, *B, *C, *D, *E, *F;

   A = (int *) table;
   B = (int *) (table + 4);
   C = (int *) (table + 8 + *A * 16);
   D = (int *) (table + 8 + *A * 16 + 4);
   E = (int *) (table + 8 + *A * 16 + 8);
   F = (int *) (table + 8 + *A * 16 + 12);

   *C = address;
   *D = port;
   *E = recent;
   *F = expectation;

   *A = *A + 1;

   return 1;
}

//获得需要的数据
int table_get_row(char *table, int sequence, int *address, int *port)
{
   int *A, *B, *C, *D;

   A = (int *) table;
   B = (int *) (table + 4);

   if (sequence >= *A)
      return 0;

   C = (int *) (table + 8 + 16 * sequence);
   D = (int *) (table + 8 + 16 * sequence + 4);

   *address = *C;
   *port = *D;

   return 1;
}

int table_get_attainment(char *table)
{
   int *B;
   B = (int *) table;

   return *B;
}

int table_get_limit(char *table)
{
   int *B;
   B = (int *) (table + 4);

   return *B;
}

//构建监听者的节点
int get_socket_alt(int address, int port)
{
   int s;
   struct sockaddr_in address;

   address.sin_family = 2;
   address.sin_port = htons(port);
   address.sin_addr.s_addr = address;

   s = socket(2, 1, 0);

   if (s == -1)
      return -1;
      
//这一步出现了问题,老师也不知道原因
   if (connect(s, (struct sockaddr *) &address, sizeof (address)) == -1)
      return -1;

   return s;
}

//构建连接者的节点
int get_socket(int port)
{
   int s;
   struct sockaddr_in address;

   address.sin_family = 2;
   address.sin_port = htons(port);
   address.sin_addr.s_addr = inet_addr("0.0.0.0");

   s = socket(2, 1, 0);

   if (s == -1)
      return -1;

   if (bind(s, (struct sockaddr *) &address, sizeof (address)) == -1)
      return -1;

   if (listen(s, 1024) == -1)
      return -1;

   return s;
}

//这里是主代码
int main(int count, char **arguments)
{
   ltc_mp = tfm_desc;
   register_prng(&sprng_desc);
   register_hash(&sha256_desc);

   int other, self, length, alternate;
   char byte;

   if ((self = get_socket(atoi(arguments[1]))) == -1)
      exit(1);

//这一步是连接上种子服务器,主动的把我的信息告诉种子服务器,但是卡在了connect那一步上面。
   if (count == 4) {

      printf("attempting to contact seed server%c", 10);
      byte = 97;
      alternate = get_socket_alt(inet_addr(arguments[2]), atoi(arguments[3]));
      printf("connection: %d%c", alternate, 10);

      send(alternate, &byte, 1, 0);
   }

   printf("listening has begun%c", 10);

   while (1) {

      if ((other = accept(self, 0, 0)) == -1)
         exit(1);

      printf("a new connection has been made%c", 10);

      int state = 0;//造一个限制状态机,还没有开始传输的状态是0,在传输中的状态是1
      int transfer = 0;

      while (1) {

         length = recv(other, &byte, 1, 0);
   
         if (length == 0 || length == -1)//接收到的长度错误或者没有,连接会断开
            break;
            
         //当接收到的ASCII码为97时,即我们输入a时,监听者会开始接收信息
         if (state == 0 && byte == 97) {
            printf("a ping was received%c", 10);
            state = 1;
            continue;
         }
         
         //将每一个收到的字符累加打印出来
         if (state == 1) {
            transfer++;
            printf("%d bytes received%c", transfer, 10);
            continue;
         }
         
         //当累加到200个字符时,则传输中断
          if (state == 1 && transfer == 200) {
            printf("transfer complete%c", 10);
            exit(1);
         }
      }
   }
}
 
5 months ago

nano 文件名
Ctrl C 查看当前行的位置
Ctrl W 搜寻关键字,并跳转
Ctrl K 剪切
Ctrl U 仅限于编辑器内的粘贴
Ctrl A 到行首
Ctrl E 到行尾
Ctrl X 退出编辑器
Ctrl J 对齐
Ctrl T 拼写检查
编辑器内的大段代码的复制和粘贴:
如果需要复制/剪贴多行或者一行中的一部分,先将光标移动到需要复制/剪贴的文本的开头,按Ctrl+6(或者Alt+A)做标记,然后移动光标到 待复制/剪贴的文本末尾。这时选定的文本会反白,用Alt+6来复制,Ctrl+K来剪贴。若在选择文本过程中要取消,只需要再按一次Ctrl+6。
Ctrl - 输入行列,并跳转
Ctrl < 桌面往左
Ctrl > 桌面往右
Command - 缩小窗口内的字
Command + 放大窗口内的字
Command < 窗口往左
Command > 窗口往右
Command tab 打开多个窗口,并打开指定窗口
Command T 新增网页
Command N 删除网页
Command Q 新增窗口
Command W 删除窗口

另外,如果想实现服务器文件和本地文件的自由传输,可以这样做:
谷歌搜索FileZilla下载,选择mac版本的,填入资料(主机是:47.94.19.190 端口:22),可以实现服务器和本地文件的转移,左边是本地,右边是服务器。

 
5 months ago
//首先调用函数仓库,函数仓库分为三种:1、操作系统的函数仓库;2、标准函数仓库;3、第三方机构或个人写的函数仓库。
其中,stdio.h(标准输出和输入的函数库)、stdlib.h(内存分配的函数库)和 string.h(字符串和内存管理函数库)都是三个标准且常用的函数仓库。
tomcrypt.h是第三方机构函数库,#define TFM_DESE是为了激活tomcrypt.h内的函数用的,是调用此函数的标准写法。

#define TFM_DESC
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "tfm.h"
#include "tomcrypt.h"

//这里是为了定义rmd160哈希函数,输出的结果是20bytes的16进制形式。
char *get_rmd160(char *buffer, int size)
{
   hash_state resource;
   char *digest;

   digest = malloc(20);
   rmd160_init(&resource);
   rmd160_process(&resource, buffer, size);
   rmd160_done(&resource, digest);

   return digest;
}

//这里是为了定义sha256哈希函数,输出的结果是32bytes的16进制形式。
char *get_sha256(char *buffer, int size)
{
   hash_state resource;
   char *digest;

   digest = malloc(32);
   sha256_init(&resource);
   sha256_process(&resource, buffer, size);
   sha256_done(&resource, digest);

   return digest;
}

//这里是定义base58check encoding的用法,目的是将生字节转换成base58字符串。
因为在直接调用这个函数方法时失败,所以将源代码粘贴到这里,所以代码看起来很长。
static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

// Thanks to Luke Dashjr.

int b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
{
   const uint8_t *bin = data;
   int carry;
   ssize_t i, j, high, zcount = 0;
   size_t size;
   
   while (zcount < binsz && !bin[zcount])
      ++zcount;
   
   size = (binsz - zcount) * 138 / 100 + 1;
   uint8_t buf[size];
   memset(buf, 0, size);
   
   for (i = zcount, high = size - 1; i < binsz; ++i, high = j)
   {
      for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
      {
         carry += 256 * buf[j];
         buf[j] = carry % 58;
         carry /= 58;
      }
   }
   
   for (j = 0; j < size && !buf[j]; ++j);
   
   if (*b58sz <= zcount + size - j)
   {
      *b58sz = zcount + size - j + 1;
      return 0;
   }
   
   if (zcount)
      memset(b58, '1', zcount);
   for (i = zcount; j < size; ++i, ++j)
      b58[i] = b58digits_ordered[buf[j]];
   b58[i] = '\0';
   *b58sz = i + 1;
   
   return 1;
}

//这里定义了scan函数用法,目的是为了获得一个物件的总长度。
因为指针指向了最开始,并且转换成了整数类型,所以代表的是这个物件的头部内容的数值,即它的总长度。
int scan(char *source)
{
   int *size;

   size = (int *) source;

   return *size;
}

//这里定义了生成私钥的用法,ecc_make_key就是生成私钥的函数,
而ecc_export是将生字节的私钥转换成了字符串的私钥,即输出的私钥是字符串形式的。
unsigned char *get_private(unsigned int *length)
{
   prng_state random;
   ecc_key key;
   unsigned char *buffer;

   buffer = malloc(*length = 1000);
   ecc_make_key(&random, find_prng("sprng"), 32, &key);
   ecc_export(buffer, length, PK_PRIVATE, &key);

   return buffer;
}

//这里定义了生成公钥的用法,ecc_import先将私钥引进来,ecc_export是将私钥转换成公钥。
unsigned char *get_public(unsigned int *length, unsigned char *private)
{
   ecc_key key;
   unsigned char *buffer;

   ecc_import(private, *length, &key);
   buffer = malloc(*length = 1000);
   ecc_export(buffer, length, PK_PUBLIC, &key);

   return buffer;
}

//这里定义了读文件的用法,先打开可读的一个文件,到最后面量出这个文件的总长度,
再回到最开始的位置,之后给其分配内存空间,将文件内容放进这个内存空间,然后关闭文件,返回文件的内容。
char *read_file(char *path, int *length) {

   FILE *file;
   char *contents;

   file = fopen(path, "r+");
   fseek(file, 0, SEEK_END);
   *length = ftell(file);
   fseek(file, 0, SEEK_SET);

   contents = malloc(*length + 1);
   fread(contents, 1, *length, file);
   fclose(file);

   return contents;
}

//这里定义了写文件的用法。
void write_file(char *path, char *substance, int length)
{
   FILE *file;

   file = fopen(path, "w");
   fwrite(substance, 1, length, file);
   fclose(file);
}

//这里定义了string_create的用法,目的是为了得到一个属性的长度和这个属性的内容。
char *string_create(char *old, int length)
{
   char *new;
   int *_6157;

   new = malloc(length + 4) + 4;
   memcpy(new, old, length);

   _6157 = (int *) (new - 4);
   *_6157 = length;

   return new;
}

//这里定义了string_create_improper的用法,目的是为了得到一个属性的长度和这个属性的内容,
跟上面的string_create的区别在于:strlen()这个函数只能测量字符串的长度,不能测量生字节的长度。
char *string_create_improper(char *old)
{
   char *new;
   int *_7193;

   new = malloc(strlen(old) + 4) + 4;
   memcpy(new, old, strlen(old));

   _7193 = (int *) (new - 4);
   *_7193 = strlen(old);

   return new;
}

//这里定义了string_measure的用法,目的是为了得到一个属性的长度,而scan是为了得到一个物件的长度。
int string_measure(char *buffer)
{
   int *_4721;

   _4721 = (int *) (buffer - 4);

   return *_4721;
}

//这里定义了构成输入的用法,将输入的几个属性有序地拼接在一起。
uint8_t *create_input(uint32_t index, uint8_t *public, uint8_t *signature, uint8_t *transaction)
{
   uint8_t *result;
   uint32_t a, b, c;

   result = malloc(48 + string_measure(public) + string_measure(signature));

   a = 48 + string_measure(public) + string_measure(signature);
   b = string_measure(public);
   c = string_measure(signature);

   memcpy(result, &a, 4);
   memcpy(result + 4, &index, 4);
   memcpy(result + 8, &b, 4);
   memcpy(result + 12, public, b);
   memcpy(result + 12 + b, &c, 4);
   memcpy(result + 16 + b, signature, c);
   memcpy(result + 16 + b + c, transaction, 32);
   return result;
}

//这里定义了构成输出的用法,将输出的几个属性有序地拼接在一起。
uint8_t *create_output(uint8_t *address, uint64_t amount)
{
   uint8_t *result;
   uint32_t a, b;

   result = malloc(16 + string_measure(address));

   a = 16 + string_measure(address);
   b = string_measure(address);

   memcpy(result, &a, 4);
   memcpy(result + 4, &b, 4);
   memcpy(result + 8, address, b);
   memcpy(result + 8 + b, &amount, 8);

   return result;
}

//这里定义了构成head的用法,将head的几个属性有序地拼接在一起。
uint8_t *create_head(uint8_t *current, uint32_t nonce, uint8_t *previous, uint8_t *target, uint32_t time, uint32_t valence)
{
   uint8_t *result;

   result = malloc(108);

   memcpy(result, current, 32);
   memcpy(result + 32, &nonce, 4); 
   memcpy(result + 36, previous, 32);
   memcpy(result + 68, target, 32);
   memcpy(result + 100, &time, 4);
   memcpy(result + 104, &valence, 4);

   return result;
}

//这里是主代码部分,首先将公钥生成了地址,根据输入和输出生成了transaction这个物件,
根据transaction又生成了head这个物件,根据transaction和head最后生成了创世block,
将这个创世块写进了一个叫1.block的文件中。
int main(int count, char **arguments)
{
//这三行是配合tomcrypt.h这个函数库的,是调用这个函数的标准写法。
   ltc_mp = tfm_desc;
   register_prng(&sprng_desc);
   register_hash(&sha256_desc);

//下面是用公钥生成地址的过程,可以参考bitcoinwiki上的流程图。
   int X, Y, Z;
   char *AA, *BB, *CC;

//打开一个公钥文件,然后将base64字符串形式的公钥转换成生字节形式的公钥(base64_decode就是起到这个作用的),
然后进行sha256哈希和rmd160哈希,得到CC。
   AA = read_file("wangjingru.public", &X);
   BB = malloc(1000);
   Y = 1000;
   base64_decode(AA, X, BB, &Y);
   CC = get_sha256(BB, Y);
   CC = get_rmd160(CC, 32);

//在CC前面增加网络版本号137,然后再进行两次sha256哈希,两次哈希是为了增加安全性,然后得到FF。
   char *FF = malloc(21);
   FF[0] = 137;
   memcpy(FF + 1, CC, 20);
   FF = get_sha256(FF, 21);
   FF = get_sha256(FF, 32);

//将FF的前面四个字节拼接到CC的后面,得到DD。
   char *DD = malloc(25);
   DD[0] = 137;
   memcpy(DD + 1, CC, 20);
   memcpy(DD + 21, FF, 4);

//将DD进行base58check encoding转换,将生字节转换成base58字符串地址。
   char *result = malloc(1000);
   int size = 1000;
   b58enc(result, &size, DD, 25);
   printf("%s%c", result, 10);

   // base64 decode
   // sha256
   // ripemd
   // sha256 sha256
   // get four

//这里是为了产生transaction的,将输入和输出拼接起来。
   char *low=result;
   low = malloc(32);

   memset(low, 0, 32);
   char *input, *output;
   char *transaction;

   int A, B, C;

   input = create_input(0, string_create(0, 0), string_create(0, 0), low);
   output = create_output(string_create_improper("xJguydL8ujwPW6uKScjkZJeg49JnLvAG4h"), 5000000000ULL);
   
   A = 12 + scan(input) + scan(output);
   B = 1;
   C = 1;

   transaction = malloc(12 + scan(input) + scan(output));
   memcpy(transaction, &A, 4);
   memcpy(transaction + 4, &B, 4);
   memcpy(transaction + 8, &C, 4);
   memcpy(transaction + 12, input, scan(input));
   memcpy(transaction + 12 + scan(input), output, scan(output));

//这里是为了生成head的,利用上面生成的transaction生成merkle根,然后定义目标高度,目标最高,即难度系数最低。
   char *previous = malloc(32);
   memset(previous, 0, 32);
   char *target = malloc(32);
   memset(target, 255, 32);
   target[0] = 0;
   target[1] = 0;
   char *head = create_head(get_sha256(transaction, scan(transaction)), 0, previous, target, time(0), 1);

   char *block = malloc(108 + scan(transaction));
   memcpy(block, head, 108);
   memcpy(block + 108, transaction, scan(transaction));

//然后将head和transaction拼接起来成为一个区块,写进1.block的文件中,即我们的创世块被创造出来了。
   write_file("1.block", block, 108 + scan(transaction));

   // a = malloc(32); memset(a, 0, 32);
   // a = malloc(32); memset(a, 255, 32);

   // current nonce previous target time valence

   // sha256(transaction)
   // 0
   // 00000000000000000...
   // yikaishi, nandu shi zui jiandan de
   // 2016 caihui tiaozheng

   // time();
   // 1

   return 0;   
}

 
5 months ago

登入阿里云账号(Linux操作系统)
linux命令行方式用 man tcc或者rm等列出相关的详细指令,用shift + Q 退出

1、复制加密库文件到自己的目录下
mkdir /home/wangjingru/tool
cd ../yuanxun
cd lib
cp libtomcrypt.a /home/wangjingru/tool (将yuanxun下面的libtomcrypt.a这个文件复制到自己的根目录下)
cd

2、新增一个文件并编辑代码
nano test-q.c

编辑如下:

#include <tomcrypt.h>
#include <stdio.h>
int main  (void){

hash_state sha256;
unsigned char  in[20], out[32], infile[100];
printf("please input infile:\n");
scanf("%s",infile);
FILE* fp=fopen(infile, "rt+");
FILE* fpout=fopen("outfile","at+");

if (fp==NULL, fpout==NULL){
        printf("cannot open the file infile or outfile");
        exit(1);
}

while (fscanf(fp, "%s", in) != EOF)
{

sha256_init(&sha256);

sha256_process(&sha256, in, strlen(in));

sha256_done(&sha256, out);

int i;
fprintf(fpout,"\n the hash result:\t", in);
printf("the hash result will be saved into outfile:\n", in);
for (i=0; i<32; i++){
fprintf(fpout,"%02x",out[i]);
printf("%02x",out[i]);
}
printf("\n");

}
fclose(fp);
fclose(fpout);

return 0;


}

3、新增专门用来输入和输出的文件
nano infile(可输入多个名字,可用空格或者换行来隔开)
touch outfile

4、编译test-q.c这个文件:
tcc -c test-q.c
源文件没有实现sha256这个函数,所以需要引用加密库来实现这个功能:
tcc -o test-q(自命名) test-q.o tool/libtomcrypt.a
(可以用tab快捷键来快速输出)

5、运行程序:
./test-q

6、输入infile这个文件名

7、检查outfile文件
nano outfile

 
5 months ago

1、在Linux服务器下运行代码
2、使用nano自命名一个文件夹名称并打开编辑
3、在编辑器中输入指令:

#include <tomcrypt.h>

int main(void)
{
hash_state sha256;

unsigned char *in = "wangjingru", hash[32];

sha256_init(&sha256);

sha256_process(&sha256, in, strlen(in));

sha256_done(&sha256, hash);

int i;
for (i=0; i<32; i++){
printf("%02x", hash[i]);
}
return 0;
}

3、编译文件:tcc -c test-w.c(将C语言编译成机器语言)
4、由于源文件中没有实现sha256这个函数,所以,连接外部的库来实现sha256这个功能:
tcc -o test-w test-w.c.o li/tool/libtomcrypt.a(libtomcrypt是一个加密库)
5、最后执行:./test-w.c(./这是指当前文件夹中找文件的意思,这是Linux的默认的习惯,不默认到当前文件就找不到。)

 
6 months ago

**Objective
关于今天的课程, 你记得什么?
学习了SQL语法:查询指令、聚合函数、在多个表中查询信息,整个过程的网速爆卡,大大拖慢了进度
完成了什么?
完成了Learn SQL的四个课时

Reflective
你要如何形容今天的情绪
因网速的影响很烦躁和焦虑,几分钟都打不开一个网页
今天的高峰是什么?
没有高峰
今天的低点是什么?
只要网速卡,就很烦躁,就准备做别的事

Interpretive
我们今天学到了什么?
SELECT 是每次要查询信息时使用的字句

WHERE 查询制定的结果

LIKE 和 BETWEEN 是在WHERE条件下使用的特殊操作符

AND 和 OR 特殊操作符,在两个或多个条件中过滤查询

ORDER BY ASC(DESC)按照升序或降序对查询结果进行排序。

LIMIT 指定查询结果返回的最大行数,否则可能会返回数百行。

LIKE 适用于相似的值之间的比较

name LIKE Se_en是name针对特定模式评估列的条件。

Se_en表示具有通配符的模式。这个 _ 意味着你可以在这里替换任何一个角色而不会破坏模式。

%是LIKE可以使用的另一个通配符,是匹配模式中零个或多个丢失字母的通配符。

A%匹配所有以“A”开头的电影
%a匹配以“a”结尾的所有电影

你也可以在模式之前和之后使用%
例如:%man%,在这里,任何包含名字“man”的电影都会返回到结果集中,但这里的LIKEb不分大小写。

BETWEEN运算符用于筛选结果在一定范围内设定。值可以是数字、文本或日期。

不过:

WHERE name BETWEEN ‘A' and ‘J'
会返回A开头的电影名字但不包括字母J开头的电影名字

WHERE year BETWEEN 1990 AND 2000
会返回1990-2000之间的电影。

聚合函数可以对数据进行计算

聚合函数将多行组合在一起形成更有意义的单个信息值

COUNT将列出名称作为参数,并计算其值不是的NULL的行数

GROUP BY是用于聚合函数的子句,用于合并来自一个或多个列的数据。

SUM( )将列名称作为参数,并返回该列中所有值的总和。

MAX( )将列名称作为参数并返回该列中的最大值。

MIN( )将列名称作为参数,并返回该列中的最小值。

AVG( )将列名称作为参数,并返回该列的平均值。

ROUND( )需要两个参数,一个列名和四舍五入该列中的值的小数位数。

主键是为表格中的行提供唯一标识符的列。此列中的值必须是唯一的,且不能是NIULL。

外健是包含数据库中另一个表主键的列。它用于标识引用表中的特定行。

SQL中使用连接来组合多个表中的数据。

INNER JOIN如果连接条件为真,则会合并不同表中的行。

LEFT OUTER JOIN将返回左表中的每一行,如果不满足连接条件,则使用NULL值来填充右表的列。

AS是SQL中的关键字,允许你使用别名重命名结果集中的列名或表名。

今天一个重要的领悟是什么?
我觉得在网速没有办法改变的情况下,要临时改变任务类型,很少用到网络的
我发现用百度浏览器很快,不用翻墙时就很快,脑子没有反应过来,意味国外的网站都要翻墙,其实试试就知道了,该用百度浏览器就能很快完成工作!

Decisional
我们会如何用一句话形容今天的工作
虽然把任务完成了,但很不爽
有哪些工作需要明天继续努力?**
快速浏览LaunchSchool:Introduction to SQL,抓取需要的信息,而不是重复的信息