random

:-)
git clone read: git://git.margiolis.net/random.git
Log | Files | Refs | LICENSE

shitcoin.c (5422B)


      1 #include <err.h>
      2 #include <stdarg.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <time.h>
      7 
      8 #include <sha256.h>
      9 
     10 #define HASH_LEN 64
     11 #define PENDING_MAX 128
     12 
     13 struct data {
     14 	char *saddr;
     15 	char *raddr;
     16 	long amount;
     17 };
     18 
     19 struct block {
     20 	struct data *data;
     21 	char hash[HASH_LEN + 1];
     22 	char prevhash[HASH_LEN + 1];
     23 	char tstmp[20];
     24 	int nonce;
     25 };
     26 
     27 struct blockchain {
     28 	struct block **blocks;
     29 	struct block *pending[PENDING_MAX];
     30 	size_t nblocks;
     31 	size_t npending;
     32 	int difficulty;
     33 	int reward;
     34 };
     35 
     36 static void transaction(const char *, const char *, long);
     37 static struct block *newblock(const char *, const char *, long, const char *);
     38 static char *calchash(struct block *);
     39 static void initchain(void);
     40 static void minepending(const char *);
     41 static void mineblock(struct block *);
     42 static int validchain(void);
     43 static struct block *lastblock(void);
     44 static long balance(const char *);
     45 static void printchain(void);
     46 static void cleanchain(void);
     47 static void *emalloc(size_t);
     48 
     49 static struct blockchain *chain;
     50 
     51 static void
     52 transaction(const char *from, const char *to, long amount)
     53 {
     54 	if (chain->npending < PENDING_MAX)
     55 		chain->pending[chain->npending++] =
     56 		    newblock(from, to, amount, NULL);
     57 	else
     58 		warnx("transaction array is full");
     59 }
     60 
     61 static struct block *
     62 newblock(const char *saddr, const char *raddr, long amount, const char *prevhash)
     63 {
     64 	struct block *b;
     65 	struct tm *tm;
     66 	time_t rtime;
     67 
     68 	b = emalloc(sizeof(struct block));
     69 	b->data = emalloc(sizeof(struct data));
     70 	b->data->saddr = strdup(saddr);
     71 	b->data->raddr = strdup(raddr);
     72 	b->data->amount = amount;
     73 	time(&rtime);
     74 	tm = localtime(&rtime);
     75 	strftime(b->tstmp, sizeof(b->tstmp), "%F %T", tm);
     76 	strcpy(b->prevhash, prevhash == NULL ? "" : prevhash);
     77 	strcpy(b->hash, calchash(b));
     78 	b->nonce = 0;
     79 
     80 	return (b);
     81 }
     82 
     83 static char *
     84 calchash(struct block *b)
     85 {
     86 	SHA256_CTX sha256;
     87 	unsigned char hash[SHA256_DIGEST_LENGTH];
     88 	char buf[HASH_LEN + 19 + strlen(b->data->saddr) + strlen(b->data->raddr) + 10 + 10 + 1];
     89 	char *res;
     90 	int i = 0;
     91 
     92 	res = emalloc(HASH_LEN + 1);
     93 	sprintf(buf, "%s%s%s%s%ld%d",
     94 	    b->prevhash, b->tstmp,
     95 	    b->data->saddr, b->data->raddr, b->data->amount, b->nonce);
     96 
     97 	SHA256_Init(&sha256);
     98 	SHA256_Update(&sha256, buf, strlen(buf));
     99 	SHA256_Final(hash, &sha256);
    100 	for (; i < SHA256_DIGEST_LENGTH; i++)
    101 		sprintf(&res[i << 1], "%02x", hash[i]);
    102 	res[HASH_LEN] = '\0';
    103 
    104 	return (res);
    105 }
    106 
    107 static void
    108 initchain(void)
    109 {
    110 	chain = emalloc(sizeof(struct blockchain));
    111 	chain->blocks = emalloc(sizeof(struct block *));
    112 	memset(chain->pending, 0, sizeof(chain->pending));
    113 	chain->nblocks = 1;
    114 	chain->npending = 0;
    115 	chain->difficulty = 4;
    116 	chain->reward = 100;
    117 	chain->blocks[0] = newblock("Genesis", "Genesis", 0, "0");
    118 }
    119 
    120 static void
    121 minepending(const char *rewaddr)
    122 {
    123 	struct block *b, *last;
    124 	int i = 0;
    125 
    126 	if (chain->npending < 1)
    127 		return;
    128 
    129 	if ((chain->blocks = realloc(chain->blocks,
    130 	    sizeof(struct block *) * (chain->nblocks + chain->npending + 1))) == NULL)
    131 		err(1, "realloc");
    132 
    133 	for (; i < chain->npending; i++) {
    134 		b = chain->pending[i];
    135 		last = lastblock();
    136 		if (!strcmp(b->prevhash, ""))
    137 			strcpy(b->prevhash, last->hash);
    138 		mineblock(b);
    139 		chain->blocks[chain->nblocks++] = b;
    140 	}
    141 	chain->npending = 0;
    142 	memset(chain->pending, 0, sizeof(chain->pending));
    143 	transaction("Mining Award", rewaddr, chain->reward);
    144 }
    145 
    146 static void
    147 mineblock(struct block *b)
    148 {
    149 	int d = chain->difficulty, i = 0;
    150 	char z[d];
    151 
    152 	for (; i < d; i++)
    153 		z[i] = '0';
    154 	while (strncmp(b->hash, z, d)) {
    155 		b->nonce++;
    156 		strcpy(b->hash, calchash(b));
    157 	}
    158 	printf("struct block mined: %s\n", b->hash);
    159 }
    160 static struct block *
    161 lastblock(void)
    162 {
    163 	return (chain->blocks[chain->nblocks - 1]);
    164 }
    165 
    166 static int
    167 validchain(void)
    168 {
    169 	int i = 0;
    170 
    171 	for (; i < chain->nblocks; i++) {
    172 		if (i != 0 && strcmp(chain->blocks[i]->prevhash,
    173 		    chain->blocks[i-1]->hash))
    174 			return (0);
    175 		if (i != 0 && strcmp(chain->blocks[i]->hash,
    176 		    calchash(chain->blocks[i])))
    177 			return (0);
    178 	}
    179 
    180 	return (1);
    181 }
    182 
    183 static long
    184 balance(const char *addr)
    185 {
    186 	long bal = 0;
    187 	int i;
    188 
    189 	for (i = 0; i < chain->nblocks; i++) {
    190 		if (!strcmp(chain->blocks[i]->data->saddr, addr))
    191 			bal -= chain->blocks[i]->data->amount;
    192 		if (!strcmp(chain->blocks[i]->data->raddr, addr))
    193 			bal += chain->blocks[i]->data->amount;
    194 	}
    195 
    196 	return (bal);
    197 }
    198 
    199 static void
    200 printchain(void)
    201 {
    202 	int i = 0;
    203 
    204 	for (; i < chain->nblocks; i++) {
    205 		printf("HASH:	    %s\n", chain->blocks[i]->hash);
    206 		printf("PREVHASH:   %s\n", chain->blocks[i]->prevhash);
    207 		printf("TIMESTAMP:  %s\n", chain->blocks[i]->tstmp);
    208 		printf("DATA:\n");
    209 		printf("    FROM:   %s\n", chain->blocks[i]->data->saddr);
    210 		printf("    TO:     %s\n", chain->blocks[i]->data->raddr);
    211 		printf("    AMOUNT: %ld\n", chain->blocks[i]->data->amount);
    212 		printf("\n");
    213 	}
    214 }
    215 
    216 static void
    217 cleanchain(void)
    218 {
    219 	int i = 0;
    220 
    221 	for (; i < chain->nblocks; i++) {
    222 		free(chain->blocks[i]->data->saddr);
    223 		free(chain->blocks[i]->data->raddr);
    224 		free(chain->blocks[i]->data);
    225 		free(chain->blocks[i]);
    226 	}
    227 	free(chain->blocks);
    228 	free(chain);
    229 }
    230 
    231 static void *
    232 emalloc(size_t nb)
    233 {
    234 	void *p;
    235 
    236 	if ((p = malloc(nb)) == NULL)
    237 		err(1, "malloc");
    238 
    239 	return (p);
    240 }
    241 
    242 int
    243 main(int argc, char *argv[])
    244 {
    245 	initchain();
    246 
    247 	transaction("Christos", "Lol", 1000);
    248 	transaction("N", "Lol", 1000);
    249 	minepending("miner");
    250 
    251 	printchain();
    252 	printf("Valid chain: %s\n", validchain() ? "Yes" : "No");
    253 	printf("Lol's balance: %ld\n", balance("Lol"));
    254 
    255 	cleanchain();
    256 
    257 	return (0);
    258 }