/******************************************************************************
* Copyright © 2014 - 2015 The SuperNET Developers . *
* *
* See the AUTHORS , DEVELOPER - AGREEMENT and LICENSE files at *
* the top - level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing . *
* *
* Unless otherwise agreed in a custom licensing agreement , no part of the *
* SuperNET software , including this file may be copied , modified , propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "iguana777.h"
# define iguana_blockfind(coin,hash2) iguana_blockhashset(coin,-1,hash2,0)
void _iguana_blocklink ( struct iguana_info * coin , struct iguana_block * prev , struct iguana_block * block )
{
char str [ 65 ] , str2 [ 65 ] ; struct iguana_block * next ;
if ( memcmp ( block - > RO . prev_block . bytes , prev - > RO . hash2 . bytes , sizeof ( bits256 ) ) ! = 0 )
{
printf ( " illegal blocklink mismatched hashes \n " ) ;
exit ( - 1 ) ;
return ;
}
block - > hh . prev = prev ;
if ( ( next = prev - > hh . next ) ! = 0 )
{
if ( next ! = block )
{
if ( memcmp ( next - > RO . prev_block . bytes , prev - > RO . hash2 . bytes , sizeof ( bits256 ) ) ! = 0 )
{
printf ( " illegal blocklink next mismatched hashes \n " ) ;
return ;
}
if ( memcmp ( next - > RO . hash2 . bytes , block - > RO . hash2 . bytes , sizeof ( bits256 ) ) ! = 0 )
printf ( " blocklink collision: %s vs %s \n " , bits256_str ( str , block - > RO . hash2 ) , bits256_str ( str2 , next - > RO . hash2 ) ) ;
else printf ( " blocklink corruption: identical hashes with diff ptrs %s %p %p \n " , bits256_str ( str , block - > RO . hash2 ) , block , next ) ;
}
prev - > hh . next = block ; // could make a linked list of all at same height for multibranch
} else prev - > hh . next = block ;
printf ( " link.(%s) -> (%s) \n " , bits256_str ( str , prev - > RO . hash2 ) , bits256_str ( str , block - > RO . hash2 ) ) ;
}
struct iguana_block * iguana_blockhashset ( struct iguana_info * coin , int32_t height , bits256 hash2 , int32_t createflag )
{
static int depth ;
struct iguana_block * block , * prev ;
if ( height > 0 & & ( height > coin - > blocks . maxbits | | depth ! = 0 ) )
{
printf ( " illegal height.%d when max.%d, depth.%d \n " , height , coin - > blocks . maxbits , depth ) ;
//getchar();
return ( 0 ) ;
}
depth + + ;
//portable_mutex_lock(&coin->blocks_mutex);
HASH_FIND ( hh , coin - > blocks . hash , & hash2 , sizeof ( hash2 ) , block ) ;
if ( block ! = 0 )
{
//portable_mutex_unlock(&coin->blocks_mutex);
depth - - ;
return ( block ) ;
}
if ( createflag > 0 )
{
block = mycalloc ( ' x ' , 1 , sizeof ( * block ) ) ;
block - > RO . hash2 = hash2 ;
block - > hh . itemind = height , block - > height = - 1 ;
HASH_ADD ( hh , coin - > blocks . hash , RO . hash2 , sizeof ( hash2 ) , block ) ;
block - > hh . next = block - > hh . prev = 0 ;
if ( bits256_nonz ( block - > RO . prev_block ) > 0 )
{
HASH_FIND ( hh , coin - > blocks . hash , & block - > RO . prev_block , sizeof ( block - > RO . prev_block ) , prev ) ;
if ( prev ! = 0 )
_iguana_blocklink ( coin , prev , block ) ;
}
//char str[65]; printf("added.(%s) height.%d (%p %p)\n",bits256_str(str,hash2),height,block->hh.prev,block->hh.next);
if ( 0 )
{
struct iguana_block * tmp ;
HASH_FIND ( hh , coin - > blocks . hash , & hash2 , sizeof ( hash2 ) , tmp ) ;
char str [ 65 ] ;
bits256_str ( str , hash2 ) ;
if ( tmp ! = block )
printf ( " %s height.%d search error %p != %p \n " , str , height , block , tmp ) ;
}
}
//portable_mutex_unlock(&coin->blocks_mutex);
depth - - ;
return ( block ) ;
}
bits256 * iguana_blockhashptr ( struct iguana_info * coin , int32_t height )
{
int32_t i ; struct iguana_bundle * bp ; bits256 * hashptr ;
if ( height > = 0 )
{
for ( i = 0 ; i < coin - > bundlescount ; i + + )
{
if ( ( bp = coin - > bundles [ i ] ) ! = 0 )
{
if ( height > = bp - > bundleheight & & height < bp - > bundleheight + bp - > n )
{
hashptr = & bp - > hashes [ height - bp - > bundleheight ] ;
//printf("i.%d hashptr.%p height.%d vs (%d %d)\n",i,hashptr,height,bp->bundleheight,bp->bundleheight+bp->n);
return ( hashptr ) ;
}
}
}
}
return ( 0 ) ;
}
bits256 iguana_blockhash ( struct iguana_info * coin , int32_t height )
{
bits256 * hash2p ; static const bits256 zero ;
if ( ( hash2p = iguana_blockhashptr ( coin , height ) ) ! = 0 )
return ( * hash2p ) ;
return ( zero ) ;
}
struct iguana_block * iguana_blockptr ( struct iguana_info * coin , int32_t height )
{
static const bits256 zero ; bits256 hash2 = iguana_blockhash ( coin , height ) ;
if ( memcmp ( zero . bytes , hash2 . bytes , sizeof ( zero ) ) ! = 0 )
return ( iguana_blockfind ( coin , hash2 ) ) ;
return ( 0 ) ;
}
int32_t iguana_blockvalidate ( struct iguana_info * coin , int32_t * validp , struct iguana_block * block )
{
bits256 hash2 ; uint8_t serialized [ sizeof ( struct iguana_msgblock ) + 4096 ] ;
* validp = 0 ;
iguana_serialize_block ( & hash2 , serialized , block ) ;
* validp = ( memcmp ( hash2 . bytes , block - > RO . hash2 . bytes , sizeof ( hash2 ) ) = = 0 ) ;
block - > valid = * validp ;
char str [ 65 ] ; char str2 [ 65 ] ;
if ( * validp = = 0 )
{
printf ( " iguana_blockvalidate: miscompare (%s) vs (%s) \n " , bits256_str ( str , hash2 ) , bits256_str ( str2 , block - > RO . hash2 ) ) ;
return ( - 1 ) ;
}
return ( 0 ) ;
}
/*void iguana_mergeprevdep(struct iguana_prevdep *destlp,struct iguana_prevdep *srclp)
{
if ( srclp - > numpkinds > destlp - > numpkinds )
destlp - > numpkinds = srclp - > numpkinds ;
if ( srclp - > numtxids > destlp - > numtxids )
destlp - > numtxids = srclp - > numtxids ;
if ( srclp - > numunspents > destlp - > numunspents )
destlp - > numunspents = srclp - > numunspents ;
if ( srclp - > numspends > destlp - > numspends )
destlp - > numspends = srclp - > numspends ;
if ( srclp - > PoW > destlp - > PoW )
destlp - > PoW = srclp - > PoW ;
}
void iguana_blockmerge ( struct iguana_block * dest , struct iguana_prevdep * destlp , struct iguana_block * block , struct iguana_prevdep * srclp )
{
if ( block - > numvins > dest - > numvins )
dest - > numvins = block - > numvins ;
if ( block - > numvouts > dest - > numvouts )
dest - > numvouts = block - > numvouts ;
if ( block - > txn_count > dest - > txn_count )
dest - > txn_count = block - > txn_count ;
if ( dest - > height = = 0 )
dest - > height = block - > height ;
iguana_mergeprevdep ( destlp , srclp ) ;
} */
void iguana_blockconv ( struct iguana_block * dest , struct iguana_msgblock * msg , bits256 hash2 , int32_t height ) //uint32_t numtxids,uint32_t numunspents,uint32_t numspends,double PoW)
{
memset ( dest , 0 , sizeof ( * dest ) ) ;
dest - > RO . version = msg - > H . version ;
dest - > RO . prev_block = msg - > H . prev_block ;
dest - > RO . merkle_root = msg - > H . merkle_root ;
dest - > RO . timestamp = msg - > H . timestamp ;
dest - > RO . bits = msg - > H . bits ;
dest - > RO . nonce = msg - > H . nonce ;
dest - > RO . txn_count = msg - > txn_count ;
dest - > height = height ;
dest - > RO . hash2 = hash2 ;
}
void iguana_blockcopy ( struct iguana_info * coin , struct iguana_block * block , struct iguana_block * origblock )
{
block - > RO . hash2 = origblock - > RO . hash2 ;
block - > RO . prev_block = origblock - > RO . prev_block ;
block - > RO . merkle_root = origblock - > RO . merkle_root ;
block - > mainchain = origblock - > mainchain ;
if ( block - > fpipbits = = 0 )
block - > fpipbits = origblock - > fpipbits ;
if ( block - > RO . timestamp = = 0 )
block - > RO . timestamp = origblock - > RO . timestamp ;
if ( block - > RO . nonce = = 0 )
block - > RO . nonce = origblock - > RO . nonce ;
if ( block - > RO . bits = = 0 )
block - > RO . bits = origblock - > RO . bits ;
if ( block - > RO . txn_count = = 0 )
block - > RO . txn_count = origblock - > RO . txn_count ;
if ( block - > RO . version = = 0 )
block - > RO . version = origblock - > RO . version ;
if ( block - > mainchain = = 0 )
block - > mainchain = origblock - > mainchain ;
if ( block - > valid = = 0 )
block - > valid = origblock - > valid ;
if ( block - > RO . recvlen = = 0 )
block - > RO . recvlen = origblock - > RO . recvlen ;
}
double PoW_from_compact ( uint32_t nBits , uint8_t unitval ) // NOT consensus safe, but most of the time will be correct
{
uint32_t nbytes , nbits , i , n ; double PoW ; uint64_t mult ;
nbytes = ( nBits > > 24 ) & 0xFF ;
nbits = ( 8 * ( nbytes - 3 ) ) ;
PoW = ( nBits & 0xFFFFFF ) ;
if ( nbytes > unitval )
{
printf ( " illegal nBits.%x \n " , nBits ) ;
return ( 0. ) ;
}
if ( ( n = ( ( 8 * ( unitval - 3 ) ) - nbits ) ) ! = 0 ) // 0x1d00ffff is genesis nBits so we map that to 1.
{
//printf("nbits.%d -> n.%d\n",nbits,n);
if ( n < 64 )
PoW / = ( 1LL < < n ) ;
else // very rare case efficiency not issue
{
for ( i = 0 ; i < n ; i + + )
PoW / = 2. ;
}
}
mult = 1 ;
while ( nbytes + + < 30 )
mult < < = 8 ;
PoW = ( PoW * mult ) / ( nBits & 0xffffff ) ;
//printf("nBits.%x -> %.15f diff %.15f | n.%d unitval.%d nbytes.%d\n",nBits,PoW,1./PoW,n,unitval,nbytes);
return ( PoW ) ;
}
int32_t iguana_blockunmain ( struct iguana_info * coin , struct iguana_block * block )
{
struct iguana_block * next ; int32_t n = 0 ;
while ( block ! = 0 )
{
//printf("n.%d %p (%p %p) mainchain.%d delink %d\n",n,block,block->hh.prev,block->hh.next,block->mainchain,block->height);
block - > mainchain = 0 ;
next = block - > hh . next ;
block = next ;
n + + ;
}
if ( n > 1000 )
printf ( " delinked.%d \n " , n ) ;
return ( n ) ;
}
struct iguana_block * _iguana_chainlink ( struct iguana_info * coin , struct iguana_block * newblock )
{
int32_t valid , bundlei , height = - 1 ; struct iguana_block * hwmchain , * block = 0 , * prev = 0 , * next ;
bits256 * hash2p = 0 ; double prevPoW = 0. ;
if ( newblock = = 0 )
return ( 0 ) ;
hwmchain = & coin - > blocks . hwmchain ;
if ( ( block = iguana_blockfind ( coin , newblock - > RO . hash2 ) ) ! = 0 )
{
if ( memcmp ( coin - > chain - > genesis_hashdata , block - > RO . hash2 . bytes , sizeof ( bits256 ) ) = = 0 )
block - > PoW = PoW_from_compact ( block - > RO . bits , coin - > chain - > unitval ) , height = 0 ;
else if ( ( prev = iguana_blockfind ( coin , block - > RO . prev_block ) ) ! = 0 )
{
if ( memcmp ( prev - > RO . hash2 . bytes , coin - > blocks . hwmchain . RO . hash2 . bytes , sizeof ( bits256 ) ) = = 0 )
prev - > mainchain = 1 ;
if ( prev - > valid ! = 0 & & prev - > mainchain ! = 0 & & prev - > height > = 0 )
{
prevPoW = prev - > PoW ;
block - > PoW = PoW_from_compact ( block - > RO . bits , coin - > chain - > unitval ) + prevPoW ;
if ( ( next = prev - > hh . next ) ! = 0 )
{
if ( next - > mainchain ! = 0 & & block - > PoW < next - > PoW )
return ( 0 ) ;
hwmchain = next ;
}
height = prev - > height + 1 ;
}
else
{
char str [ 65 ] ; printf ( " (%s) notready v.%d m.%d h.%d \n " , bits256_str ( str , prev - > RO . hash2 ) , prev - > valid , prev - > mainchain , prev - > height ) ;
return ( 0 ) ;
}
}
else
{
//char str[65]; printf("chainlink error: cant find prev.(%s)\n",bits256_str(str,block->hash2));
//getchar();
return ( 0 ) ;
}
//char str[65]; printf("extend? %s.h%d: %.15f vs %.15f ht.%d vs %d\n",bits256_str(str,block->hash2),height,block->PoW,coin->blocks.hwmchain.PoW,height,coin->blocks.hwmchain.height);
if ( iguana_blockvalidate ( coin , & valid , newblock ) < 0 | | valid = = 0 )
return ( 0 ) ;
block - > height = height ;
block - > valid = 1 ;
if ( block - > PoW > = hwmchain - > PoW )
{
block - > hh . prev = prev ;
if ( prev ! = 0 )
{
//if ( prev->hh.next != block )
// iguana_blockunmain(coin,prev->hh.next);
prev - > hh . next = block ;
}
if ( coin - > isRT ! = 0 | | block - > height = = hwmchain - > height )
{
coin - > blocks . maxblocks = ( block - > height + 1 ) ;
coin - > blocks . hwmchain = * block ;
//printf("[%s] <- ht.%d\n",bits256_str(str,block->hash2),coin->blocks.hwmheight);
char str [ 65 ] , str2 [ 65 ] ; bits256 zero ;
memset ( & zero , 0 , sizeof ( zero ) ) ;
bits256_str ( str , newblock - > RO . hash2 ) ;
if ( hash2p ! = 0 )
bits256_str ( str2 , * hash2p ) ;
else str2 [ 0 ] = 0 ;
if ( block - > height + 1 > coin - > longestchain )
coin - > longestchain = block - > height + 1 ;
if ( ( block - > height % 1000 ) = = 0 )
printf ( " EXTENDMAIN %s %d <- (%s) n.%u max.%u PoW %f numtx.%d valid.%d \n " , str , block - > height , str2 , hwmchain - > height + 1 , coin - > blocks . maxblocks , block - > PoW , block - > RO . txn_count , block - > valid ) ;
struct iguana_bundle * bp ;
if ( ( block - > height % coin - > chain - > bundlesize ) = = 0 )
bp = iguana_bundlecreate ( coin , & bundlei , block - > height , block - > RO . hash2 , zero , 0 ) ;
else
{
if ( ( bp = coin - > bundles [ block - > height / coin - > chain - > bundlesize ] ) ! = 0 )
{
if ( memcmp ( bp - > hashes [ block - > height % coin - > chain - > bundlesize ] . bytes , block - > RO . hash2 . bytes , sizeof ( bits256 ) ) ! = 0 )
{
if ( bits256_nonz ( bp - > hashes [ block - > height % coin - > chain - > bundlesize ] ) > 0 )
{
printf ( " ERROR: need to fix up bundle for height.%d \n " , block - > height ) ;
//getchar();
}
bp - > hashes [ block - > height % coin - > chain - > bundlesize ] = block - > RO . hash2 ;
bp - > blocks [ block - > height % coin - > chain - > bundlesize ] = block ;
}
}
}
//if ( block->fpipbits == 0 )
// iguana_blockQ(coin,bp,block->height % coin->chain->bundlesize,block->RO.hash2,1);
block - > mainchain = 1 ;
return ( block ) ;
}
}
} else printf ( " chainlink error from block.%p \n " , block ) ;
return ( 0 ) ;
}
void iguana_blocksetheights ( struct iguana_info * coin , struct iguana_block * block )
{
int32_t height ;
if ( ( height = block - > height ) < 0 )
return ;
while ( block ! = 0 & & block - > height ! = height )
{
block - > height = height ;
iguana_bundlehash2add ( coin , 0 , coin - > bundles [ height / coin - > chain - > bundlesize ] , height % coin - > chain - > bundlesize , block - > RO . hash2 ) ;
block = block - > hh . next , height + + ;
}
}
int32_t iguana_chainextend ( struct iguana_info * coin , struct iguana_block * newblock )
{
struct iguana_block * block , * prev ; int32_t valid , oldhwm ; char str [ 65 ] ;
if ( iguana_blockvalidate ( coin , & valid , newblock ) < 0 | | valid = = 0 )
{
printf ( " chainextend: newblock.%s didnt validate \n " , bits256_str ( str , newblock - > RO . hash2 ) ) ;
return ( - 1 ) ;
}
else
{
block = iguana_blockhashset ( coin , - 1 , newblock - > RO . hash2 , 1 ) ;
if ( block ! = newblock )
iguana_blockcopy ( coin , block , newblock ) ;
block - > valid = 1 ;
if ( block - > hh . prev = = 0 & & ( prev = iguana_blockfind ( coin , block - > RO . prev_block ) ) ! = 0 )
{
if ( prev - > hh . next = = 0 & & block - > hh . prev = = 0 )
prev - > hh . next = block , block - > hh . prev = prev ;
//printf("extend newblock.%s prevm.%d\n",bits256_str(str,block->prev_block),prev->mainchain);
if ( prev - > mainchain = = 0 )
{
if ( ( block = iguana_blockfind ( coin , coin - > blocks . hwmchain . RO . hash2 ) ) ! = 0 & & block - > mainchain = = 0 )
{
//printf("c hwmchain is not mainchain anymore?\n");
prev - > mainchain = 1 ;
} else return ( 0 ) ;
}
}
if ( memcmp ( block - > RO . prev_block . bytes , coin - > blocks . hwmchain . RO . hash2 . bytes , sizeof ( bits256 ) ) ! = 0 )
return ( 0 ) ;
}
if ( block ! = 0 )
{
oldhwm = coin - > blocks . hwmchain . height ;
//printf("link.%s\n",bits256_str(str,block->hash2));
while ( block ! = 0 & & memcmp ( block - > RO . hash2 . bytes , coin - > blocks . hwmchain . RO . hash2 . bytes , sizeof ( bits256 ) ) ! = 0 & & _iguana_chainlink ( coin , block ) = = block & & coin - > blocks . hwmchain . height ! = oldhwm )
{
oldhwm = coin - > blocks . hwmchain . height ;
block = block - > hh . next ;
if ( block ! = 0 )
{
if ( bits256_nonz ( block - > RO . prev_block ) = = 0 )
break ;
//printf("next link.%s\n",bits256_str(str,block->hash2));
}
}
}
if ( ( block = iguana_blockfind ( coin , coin - > blocks . hwmchain . RO . hash2 ) ) ! = 0 & & block - > mainchain = = 0 )
{
printf ( " hwmchain is not mainchain anymore? \n " ) ;
block - > mainchain = 1 ;
}
return ( coin - > blocks . hwmchain . height ) ;
}