├── LICENSE ├── SmartpoolVersion.sol └── Testpool.sol /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 SmartPool 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SmartpoolVersion.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.9; 2 | 3 | contract SmartpoolVersion { 4 | address public poolContract; 5 | bytes32 public clientVersion; 6 | 7 | mapping (address=>bool) owners; 8 | 9 | function SmartpoolVersion( address[3] _owners ) { 10 | owners[_owners[0]] = true; 11 | owners[_owners[1]] = true; 12 | owners[_owners[2]] = true; 13 | } 14 | 15 | function updatePoolContract( address newAddress ) { 16 | if( ! owners[msg.sender] ) throw; 17 | 18 | poolContract = newAddress; 19 | } 20 | 21 | function updateClientVersion( bytes32 version ) { 22 | if( ! owners[msg.sender] ) throw; 23 | 24 | clientVersion = version; 25 | } 26 | } -------------------------------------------------------------------------------- /Testpool.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.9; 2 | 3 | //import "./SHA3_512.sol"; 4 | 5 | contract SHA3_512 { 6 | function SHA3_512() {} 7 | 8 | event Result(uint result); 9 | 10 | 11 | function keccak_f(uint[25] A) constant internal returns(uint[25]) { 12 | uint[5] memory C; 13 | uint[5] memory D; 14 | uint x; 15 | uint y; 16 | //uint D_0; uint D_1; uint D_2; uint D_3; uint D_4; 17 | uint[25] memory B; 18 | 19 | uint[24] memory RC= [ 20 | uint(0x0000000000000001), 21 | 0x0000000000008082, 22 | 0x800000000000808A, 23 | 0x8000000080008000, 24 | 0x000000000000808B, 25 | 0x0000000080000001, 26 | 0x8000000080008081, 27 | 0x8000000000008009, 28 | 0x000000000000008A, 29 | 0x0000000000000088, 30 | 0x0000000080008009, 31 | 0x000000008000000A, 32 | 0x000000008000808B, 33 | 0x800000000000008B, 34 | 0x8000000000008089, 35 | 0x8000000000008003, 36 | 0x8000000000008002, 37 | 0x8000000000000080, 38 | 0x000000000000800A, 39 | 0x800000008000000A, 40 | 0x8000000080008081, 41 | 0x8000000000008080, 42 | 0x0000000080000001, 43 | 0x8000000080008008 ]; 44 | 45 | for( uint i = 0 ; i < 24 ; i++ ) { 46 | /* 47 | for( x = 0 ; x < 5 ; x++ ) { 48 | C[x] = A[5*x]^A[5*x+1]^A[5*x+2]^A[5*x+3]^A[5*x+4]; 49 | }*/ 50 | 51 | C[0]=A[0]^A[1]^A[2]^A[3]^A[4]; 52 | C[1]=A[5]^A[6]^A[7]^A[8]^A[9]; 53 | C[2]=A[10]^A[11]^A[12]^A[13]^A[14]; 54 | C[3]=A[15]^A[16]^A[17]^A[18]^A[19]; 55 | C[4]=A[20]^A[21]^A[22]^A[23]^A[24]; 56 | 57 | /* 58 | for( x = 0 ; x < 5 ; x++ ) { 59 | D[x] = C[(x+4)%5]^((C[(x+1)%5] * 2)&0xffffffffffffffff | (C[(x+1)%5]/(2**63))); 60 | }*/ 61 | 62 | 63 | D[0]=C[4] ^ ((C[1] * 2)&0xffffffffffffffff | (C[1] / (2 ** 63))); 64 | D[1]=C[0] ^ ((C[2] * 2)&0xffffffffffffffff | (C[2] / (2 ** 63))); 65 | D[2]=C[1] ^ ((C[3] * 2)&0xffffffffffffffff | (C[3] / (2 ** 63))); 66 | D[3]=C[2] ^ ((C[4] * 2)&0xffffffffffffffff | (C[4] / (2 ** 63))); 67 | D[4]=C[3] ^ ((C[0] * 2)&0xffffffffffffffff | (C[0] / (2 ** 63))); 68 | 69 | /* 70 | for( x = 0 ; x < 5 ; x++ ) { 71 | for( y = 0 ; y < 5 ; y++ ) { 72 | A[5*x+y] = A[5*x+y] ^ D[x]; 73 | } 74 | }*/ 75 | 76 | 77 | 78 | A[0]=A[0] ^ D[0]; 79 | A[1]=A[1] ^ D[0]; 80 | A[2]=A[2] ^ D[0]; 81 | A[3]=A[3] ^ D[0]; 82 | A[4]=A[4] ^ D[0]; 83 | A[5]=A[5] ^ D[1]; 84 | A[6]=A[6] ^ D[1]; 85 | A[7]=A[7] ^ D[1]; 86 | A[8]=A[8] ^ D[1]; 87 | A[9]=A[9] ^ D[1]; 88 | A[10]=A[10] ^ D[2]; 89 | A[11]=A[11] ^ D[2]; 90 | A[12]=A[12] ^ D[2]; 91 | A[13]=A[13] ^ D[2]; 92 | A[14]=A[14] ^ D[2]; 93 | A[15]=A[15] ^ D[3]; 94 | A[16]=A[16] ^ D[3]; 95 | A[17]=A[17] ^ D[3]; 96 | A[18]=A[18] ^ D[3]; 97 | A[19]=A[19] ^ D[3]; 98 | A[20]=A[20] ^ D[4]; 99 | A[21]=A[21] ^ D[4]; 100 | A[22]=A[22] ^ D[4]; 101 | A[23]=A[23] ^ D[4]; 102 | A[24]=A[24] ^ D[4]; 103 | 104 | /*Rho and pi steps*/ 105 | B[0]=A[0]; 106 | B[8]=((A[1] * (2 ** 36))&0xffffffffffffffff | (A[1] / (2 ** 28))); 107 | B[11]=((A[2] * (2 ** 3))&0xffffffffffffffff | (A[2] / (2 ** 61))); 108 | B[19]=((A[3] * (2 ** 41))&0xffffffffffffffff | (A[3] / (2 ** 23))); 109 | B[22]=((A[4] * (2 ** 18))&0xffffffffffffffff | (A[4] / (2 ** 46))); 110 | B[2]=((A[5] * (2 ** 1))&0xffffffffffffffff | (A[5] / (2 ** 63))); 111 | B[5]=((A[6] * (2 ** 44))&0xffffffffffffffff | (A[6] / (2 ** 20))); 112 | B[13]=((A[7] * (2 ** 10))&0xffffffffffffffff | (A[7] / (2 ** 54))); 113 | B[16]=((A[8] * (2 ** 45))&0xffffffffffffffff | (A[8] / (2 ** 19))); 114 | B[24]=((A[9] * (2 ** 2))&0xffffffffffffffff | (A[9] / (2 ** 62))); 115 | B[4]=((A[10] * (2 ** 62))&0xffffffffffffffff | (A[10] / (2 ** 2))); 116 | B[7]=((A[11] * (2 ** 6))&0xffffffffffffffff | (A[11] / (2 ** 58))); 117 | B[10]=((A[12] * (2 ** 43))&0xffffffffffffffff | (A[12] / (2 ** 21))); 118 | B[18]=((A[13] * (2 ** 15))&0xffffffffffffffff | (A[13] / (2 ** 49))); 119 | B[21]=((A[14] * (2 ** 61))&0xffffffffffffffff | (A[14] / (2 ** 3))); 120 | B[1]=((A[15] * (2 ** 28))&0xffffffffffffffff | (A[15] / (2 ** 36))); 121 | B[9]=((A[16] * (2 ** 55))&0xffffffffffffffff | (A[16] / (2 ** 9))); 122 | B[12]=((A[17] * (2 ** 25))&0xffffffffffffffff | (A[17] / (2 ** 39))); 123 | B[15]=((A[18] * (2 ** 21))&0xffffffffffffffff | (A[18] / (2 ** 43))); 124 | B[23]=((A[19] * (2 ** 56))&0xffffffffffffffff | (A[19] / (2 ** 8))); 125 | B[3]=((A[20] * (2 ** 27))&0xffffffffffffffff | (A[20] / (2 ** 37))); 126 | B[6]=((A[21] * (2 ** 20))&0xffffffffffffffff | (A[21] / (2 ** 44))); 127 | B[14]=((A[22] * (2 ** 39))&0xffffffffffffffff | (A[22] / (2 ** 25))); 128 | B[17]=((A[23] * (2 ** 8))&0xffffffffffffffff | (A[23] / (2 ** 56))); 129 | B[20]=((A[24] * (2 ** 14))&0xffffffffffffffff | (A[24] / (2 ** 50))); 130 | 131 | /*Xi state*/ 132 | /* 133 | for( x = 0 ; x < 5 ; x++ ) { 134 | for( y = 0 ; y < 5 ; y++ ) { 135 | A[5*x+y] = B[5*x+y]^((~B[5*((x+1)%5)+y]) & B[5*((x+2)%5)+y]); 136 | } 137 | }*/ 138 | 139 | 140 | A[0]=B[0]^((~B[5]) & B[10]); 141 | A[1]=B[1]^((~B[6]) & B[11]); 142 | A[2]=B[2]^((~B[7]) & B[12]); 143 | A[3]=B[3]^((~B[8]) & B[13]); 144 | A[4]=B[4]^((~B[9]) & B[14]); 145 | A[5]=B[5]^((~B[10]) & B[15]); 146 | A[6]=B[6]^((~B[11]) & B[16]); 147 | A[7]=B[7]^((~B[12]) & B[17]); 148 | A[8]=B[8]^((~B[13]) & B[18]); 149 | A[9]=B[9]^((~B[14]) & B[19]); 150 | A[10]=B[10]^((~B[15]) & B[20]); 151 | A[11]=B[11]^((~B[16]) & B[21]); 152 | A[12]=B[12]^((~B[17]) & B[22]); 153 | A[13]=B[13]^((~B[18]) & B[23]); 154 | A[14]=B[14]^((~B[19]) & B[24]); 155 | A[15]=B[15]^((~B[20]) & B[0]); 156 | A[16]=B[16]^((~B[21]) & B[1]); 157 | A[17]=B[17]^((~B[22]) & B[2]); 158 | A[18]=B[18]^((~B[23]) & B[3]); 159 | A[19]=B[19]^((~B[24]) & B[4]); 160 | A[20]=B[20]^((~B[0]) & B[5]); 161 | A[21]=B[21]^((~B[1]) & B[6]); 162 | A[22]=B[22]^((~B[2]) & B[7]); 163 | A[23]=B[23]^((~B[3]) & B[8]); 164 | A[24]=B[24]^((~B[4]) & B[9]); 165 | 166 | /*Last step*/ 167 | A[0]=A[0]^RC[i]; 168 | } 169 | 170 | 171 | return A; 172 | } 173 | 174 | 175 | function sponge(uint[9] M) constant internal returns(uint[16]) { 176 | if( (M.length * 8) != 72 ) throw; 177 | M[5] = 0x01; 178 | M[8] = 0x8000000000000000; 179 | 180 | uint r = 72; 181 | uint w = 8; 182 | uint size = M.length * 8; 183 | 184 | uint[25] memory S; 185 | uint i; uint y; uint x; 186 | /*Absorbing Phase*/ 187 | for( i = 0 ; i < size/r ; i++ ) { 188 | for( y = 0 ; y < 5 ; y++ ) { 189 | for( x = 0 ; x < 5 ; x++ ) { 190 | if( (x+5*y) < (r/w) ) { 191 | S[5*x+y] = S[5*x+y] ^ M[i*9 + x + 5*y]; 192 | } 193 | } 194 | } 195 | S = keccak_f(S); 196 | } 197 | 198 | /*Squeezing phase*/ 199 | uint[16] memory result; 200 | uint b = 0; 201 | while( b < 16 ) { 202 | for( y = 0 ; y < 5 ; y++ ) { 203 | for( x = 0 ; x < 5 ; x++ ) { 204 | if( (x+5*y)<(r/w) && (b<16) ) { 205 | result[b] = S[5*x+y] & 0xFFFFFFFF; 206 | result[b+1] = S[5*x+y] / 0x100000000; 207 | b+=2; 208 | } 209 | } 210 | } 211 | } 212 | 213 | return result; 214 | } 215 | 216 | } 217 | 218 | //////////////////////////////////////////////////////////////////////////////// 219 | 220 | contract Ethash is SHA3_512 { 221 | 222 | 223 | function Ethash() { 224 | } 225 | 226 | function fnv( uint v1, uint v2 ) constant internal returns(uint) { 227 | return ((v1*0x01000193) ^ v2) & 0xFFFFFFFF; 228 | } 229 | 230 | 231 | 232 | function computeCacheRoot( uint index, 233 | uint indexInElementsArray, 234 | uint[] elements, 235 | uint[] witness, 236 | uint branchSize ) constant private returns(uint) { 237 | 238 | 239 | uint leaf = computeLeaf(elements, indexInElementsArray) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 240 | 241 | uint left; 242 | uint right; 243 | uint node; 244 | bool oddBranchSize = (branchSize % 2) > 0; 245 | 246 | assembly { 247 | branchSize := div(branchSize,2) 248 | //branchSize /= 2; 249 | } 250 | uint witnessIndex = indexInElementsArray * branchSize; 251 | if( oddBranchSize ) witnessIndex += indexInElementsArray; 252 | 253 | for( uint depth = 0 ; depth < branchSize ; depth++ ) { 254 | assembly { 255 | node := mload(add(add(witness,0x20),mul(add(depth,witnessIndex),0x20))) 256 | } 257 | //node = witness[witnessIndex + depth] & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 258 | if( index & 0x1 == 0 ) { 259 | left = leaf; 260 | assembly{ 261 | //right = node & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 262 | right := and(node,0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) 263 | } 264 | 265 | } 266 | else { 267 | assembly{ 268 | //left = node & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 269 | left := and(node,0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) 270 | } 271 | right = leaf; 272 | } 273 | 274 | leaf = uint(sha3(left,right)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 275 | assembly { 276 | index := div(index,2) 277 | } 278 | //index = index / 2; 279 | 280 | //node = witness[witnessIndex + depth] / (2**128); 281 | if( index & 0x1 == 0 ) { 282 | left = leaf; 283 | assembly{ 284 | right := div(node,0x100000000000000000000000000000000) 285 | //right = node / 0x100000000000000000000000000000000; 286 | } 287 | } 288 | else { 289 | assembly { 290 | //left = node / 0x100000000000000000000000000000000; 291 | left := div(node,0x100000000000000000000000000000000) 292 | } 293 | right = leaf; 294 | } 295 | 296 | leaf = uint(sha3(left,right)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 297 | assembly { 298 | index := div(index,2) 299 | } 300 | //index = index / 2; 301 | } 302 | 303 | if( oddBranchSize ) { 304 | assembly { 305 | node := mload(add(add(witness,0x20),mul(add(depth,witnessIndex),0x20))) 306 | } 307 | 308 | //node = witness[witnessIndex + depth] & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 309 | if( index & 0x1 == 0 ) { 310 | left = leaf; 311 | assembly{ 312 | //right = node & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 313 | right := and(node,0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) 314 | } 315 | } 316 | else { 317 | assembly{ 318 | //left = node & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 319 | left := and(node,0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) 320 | } 321 | 322 | right = leaf; 323 | } 324 | 325 | leaf = uint(sha3(left,right)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 326 | } 327 | 328 | 329 | return leaf; 330 | } 331 | 332 | 333 | function toBE( uint x ) constant internal returns(uint) { 334 | uint y = 0; 335 | for( uint i = 0 ; i < 32 ; i++ ) { 336 | y = y * 256; 337 | y += (x & 0xFF); 338 | x = x / 256; 339 | } 340 | 341 | return y; 342 | 343 | } 344 | 345 | function computeSha3( uint[16] s, uint[8] cmix ) constant internal returns(uint) { 346 | uint s0 = s[0] + s[1] * (2**32) + s[2] * (2**64) + s[3] * (2**96) + 347 | (s[4] + s[5] * (2**32) + s[6] * (2**64) + s[7] * (2**96))*(2**128); 348 | 349 | uint s1 = s[8] + s[9] * (2**32) + s[10] * (2**64) + s[11] * (2**96) + 350 | (s[12] + s[13] * (2**32) + s[14] * (2**64) + s[15] * (2**96))*(2**128); 351 | 352 | uint c = cmix[0] + cmix[1] * (2**32) + cmix[2] * (2**64) + cmix[3] * (2**96) + 353 | (cmix[4] + cmix[5] * (2**32) + cmix[6] * (2**64) + cmix[7] * (2**96))*(2**128); 354 | 355 | 356 | /* god knows why need to convert to big endian */ 357 | return uint( sha3(toBE(s0),toBE(s1),toBE(c)) ); 358 | } 359 | 360 | 361 | function computeLeaf( uint[] dataSetLookup, uint index ) constant internal returns(uint) { 362 | return uint( sha3(dataSetLookup[4*index], 363 | dataSetLookup[4*index + 1], 364 | dataSetLookup[4*index + 2], 365 | dataSetLookup[4*index + 3]) ); 366 | 367 | } 368 | 369 | function computeS( uint header, uint nonceLe ) constant internal returns(uint[16]) { 370 | uint[9] memory M; 371 | 372 | header = reverseBytes(header); 373 | 374 | M[0] = uint(header) & 0xFFFFFFFFFFFFFFFF; 375 | header = header / 2**64; 376 | M[1] = uint(header) & 0xFFFFFFFFFFFFFFFF; 377 | header = header / 2**64; 378 | M[2] = uint(header) & 0xFFFFFFFFFFFFFFFF; 379 | header = header / 2**64; 380 | M[3] = uint(header) & 0xFFFFFFFFFFFFFFFF; 381 | 382 | // make little endian nonce 383 | M[4] = nonceLe; 384 | return sponge(M); 385 | } 386 | 387 | function reverseBytes( uint input ) constant internal returns(uint) { 388 | uint result = 0; 389 | for(uint i = 0 ; i < 32 ; i++ ) { 390 | result = result * 256; 391 | result += input & 0xff; 392 | 393 | input /= 256; 394 | } 395 | 396 | return result; 397 | } 398 | 399 | event Log( uint result ); 400 | function hashimoto( bytes32 header, 401 | bytes8 nonceLe, 402 | uint fullSizeIn128Resultion, 403 | uint[] dataSetLookup, 404 | uint[] witnessForLookup, 405 | uint branchSize, 406 | uint root ) constant returns(uint) { 407 | 408 | uint[16] memory s; 409 | uint[32] memory mix; 410 | uint[8] memory cmix; 411 | 412 | uint i; 413 | uint j; 414 | 415 | 416 | 417 | s = computeS(uint(header), uint(nonceLe)); 418 | for( i = 0 ; i < 16 ; i++ ) { 419 | assembly { 420 | let offset := mul(i,0x20) 421 | 422 | //mix[i] = s[i]; 423 | mstore(add(mix,offset),mload(add(s,offset))) 424 | 425 | // mix[i+16] = s[i]; 426 | mstore(add(mix,add(0x200,offset)),mload(add(s,offset))) 427 | } 428 | } 429 | 430 | for( i = 0 ; i < 64 ; i++ ) { 431 | uint p = fnv( i ^ s[0], mix[i % 32]) % fullSizeIn128Resultion; 432 | if( computeCacheRoot( p, i, dataSetLookup, witnessForLookup, branchSize ) != root ) { 433 | // PoW failed 434 | return 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 435 | } 436 | 437 | for( j = 0 ; j < 8 ; j++ ) { 438 | 439 | assembly{ 440 | //mix[j] = fnv(mix[j], dataSetLookup[4*i] & varFFFFFFFF ); 441 | let dataOffset := add(mul(0x80,i),add(dataSetLookup,0x20)) 442 | let dataValue := and(mload(dataOffset),0xFFFFFFFF) 443 | 444 | let mixOffset := add(mix,mul(0x20,j)) 445 | let mixValue := mload(mixOffset) 446 | 447 | // fnv = return ((v1*0x01000193) ^ v2) & 0xFFFFFFFF; 448 | let fnvValue := and(xor(mul(mixValue,0x01000193),dataValue),0xFFFFFFFF) 449 | mstore(mixOffset,fnvValue) 450 | 451 | //mix[j+8] = fnv(mix[j+8], dataSetLookup[4*i + 1] & 0xFFFFFFFF ); 452 | dataOffset := add(dataOffset,0x20) 453 | dataValue := and(mload(dataOffset),0xFFFFFFFF) 454 | 455 | mixOffset := add(mixOffset,0x100) 456 | mixValue := mload(mixOffset) 457 | 458 | // fnv = return ((v1*0x01000193) ^ v2) & 0xFFFFFFFF; 459 | let fnvValue := and(xor(mul(mixValue,0x01000193),dataValue),0xFFFFFFFF) 460 | mstore(mixOffset,fnvValue) 461 | 462 | //mix[j+16] = fnv(mix[j+16], dataSetLookup[4*i + 2] & 0xFFFFFFFF ); 463 | dataOffset := add(dataOffset,0x20) 464 | dataValue := and(mload(dataOffset),0xFFFFFFFF) 465 | 466 | mixOffset := add(mixOffset,0x100) 467 | mixValue := mload(mixOffset) 468 | 469 | // fnv = return ((v1*0x01000193) ^ v2) & 0xFFFFFFFF; 470 | let fnvValue := and(xor(mul(mixValue,0x01000193),dataValue),0xFFFFFFFF) 471 | mstore(mixOffset,fnvValue) 472 | 473 | //mix[j+24] = fnv(mix[j+24], dataSetLookup[4*i + 3] & 0xFFFFFFFF ); 474 | dataOffset := add(dataOffset,0x20) 475 | dataValue := and(mload(dataOffset),0xFFFFFFFF) 476 | 477 | mixOffset := add(mixOffset,0x100) 478 | mixValue := mload(mixOffset) 479 | 480 | // fnv = return ((v1*0x01000193) ^ v2) & 0xFFFFFFFF; 481 | let fnvValue := and(xor(mul(mixValue,0x01000193),dataValue),0xFFFFFFFF) 482 | mstore(mixOffset,fnvValue) 483 | 484 | } 485 | 486 | 487 | //mix[j] = fnv(mix[j], dataSetLookup[4*i] & 0xFFFFFFFF ); 488 | //mix[j+8] = fnv(mix[j+8], dataSetLookup[4*i + 1] & 0xFFFFFFFF ); 489 | //mix[j+16] = fnv(mix[j+16], dataSetLookup[4*i + 2] & 0xFFFFFFFF ); 490 | //mix[j+24] = fnv(mix[j+24], dataSetLookup[4*i + 3] & 0xFFFFFFFF ); 491 | 492 | 493 | //dataSetLookup[4*i ] = dataSetLookup[4*i ]/(2**32); 494 | //dataSetLookup[4*i + 1] = dataSetLookup[4*i + 1]/(2**32); 495 | //dataSetLookup[4*i + 2] = dataSetLookup[4*i + 2]/(2**32); 496 | //dataSetLookup[4*i + 3] = dataSetLookup[4*i + 3]/(2**32); 497 | 498 | assembly{ 499 | let offset := add(add(dataSetLookup,0x20),mul(i,0x80)) 500 | let value := div(mload(offset),0x100000000) 501 | mstore(offset,value) 502 | 503 | offset := add(offset,0x20) 504 | value := div(mload(offset),0x100000000) 505 | mstore(offset,value) 506 | 507 | offset := add(offset,0x20) 508 | value := div(mload(offset),0x100000000) 509 | mstore(offset,value) 510 | 511 | offset := add(offset,0x20) 512 | value := div(mload(offset),0x100000000) 513 | mstore(offset,value) 514 | } 515 | } 516 | } 517 | 518 | 519 | for( i = 0 ; i < 32 ; i += 4) { 520 | cmix[i/4] = (fnv(fnv(fnv(mix[i], mix[i+1]), mix[i+2]), mix[i+3])); 521 | } 522 | 523 | 524 | uint result = computeSha3(s,cmix); 525 | Log(result); 526 | return result; 527 | 528 | } 529 | } 530 | 531 | /** 532 | * @title RLPReader 533 | * 534 | * RLPReader is used to read and parse RLP encoded data in memory. 535 | * 536 | * @author Andreas Olofsson (androlo1980@gmail.com) 537 | */ 538 | library RLP { 539 | 540 | uint constant DATA_SHORT_START = 0x80; 541 | uint constant DATA_LONG_START = 0xB8; 542 | uint constant LIST_SHORT_START = 0xC0; 543 | uint constant LIST_LONG_START = 0xF8; 544 | 545 | uint constant DATA_LONG_OFFSET = 0xB7; 546 | uint constant LIST_LONG_OFFSET = 0xF7; 547 | 548 | 549 | struct RLPItem { 550 | uint _unsafe_memPtr; // Pointer to the RLP-encoded bytes. 551 | uint _unsafe_length; // Number of bytes. This is the full length of the string. 552 | } 553 | 554 | struct Iterator { 555 | RLPItem _unsafe_item; // Item that's being iterated over. 556 | uint _unsafe_nextPtr; // Position of the next item in the list. 557 | } 558 | 559 | /* Iterator */ 560 | 561 | function next(Iterator memory self) internal constant returns (RLPItem memory subItem) { 562 | if(hasNext(self)) { 563 | var ptr = self._unsafe_nextPtr; 564 | var itemLength = _itemLength(ptr); 565 | subItem._unsafe_memPtr = ptr; 566 | subItem._unsafe_length = itemLength; 567 | self._unsafe_nextPtr = ptr + itemLength; 568 | } 569 | else 570 | throw; 571 | } 572 | 573 | function next(Iterator memory self, bool strict) internal constant returns (RLPItem memory subItem) { 574 | subItem = next(self); 575 | if(strict && !_validate(subItem)) 576 | throw; 577 | return; 578 | } 579 | 580 | function hasNext(Iterator memory self) internal constant returns (bool) { 581 | var item = self._unsafe_item; 582 | return self._unsafe_nextPtr < item._unsafe_memPtr + item._unsafe_length; 583 | } 584 | 585 | /* RLPItem */ 586 | 587 | /// @dev Creates an RLPItem from an array of RLP encoded bytes. 588 | /// @param self The RLP encoded bytes. 589 | /// @return An RLPItem 590 | function toRLPItem(bytes memory self) internal constant returns (RLPItem memory) { 591 | uint len = self.length; 592 | if (len == 0) { 593 | return RLPItem(0, 0); 594 | } 595 | uint memPtr; 596 | assembly { 597 | memPtr := add(self, 0x20) 598 | } 599 | return RLPItem(memPtr, len); 600 | } 601 | 602 | /// @dev Creates an RLPItem from an array of RLP encoded bytes. 603 | /// @param self The RLP encoded bytes. 604 | /// @param strict Will throw if the data is not RLP encoded. 605 | /// @return An RLPItem 606 | function toRLPItem(bytes memory self, bool strict) internal constant returns (RLPItem memory) { 607 | var item = toRLPItem(self); 608 | if(strict) { 609 | uint len = self.length; 610 | if(_payloadOffset(item) > len) 611 | throw; 612 | if(_itemLength(item._unsafe_memPtr) != len) 613 | throw; 614 | if(!_validate(item)) 615 | throw; 616 | } 617 | return item; 618 | } 619 | 620 | /// @dev Check if the RLP item is null. 621 | /// @param self The RLP item. 622 | /// @return 'true' if the item is null. 623 | function isNull(RLPItem memory self) internal constant returns (bool ret) { 624 | return self._unsafe_length == 0; 625 | } 626 | 627 | /// @dev Check if the RLP item is a list. 628 | /// @param self The RLP item. 629 | /// @return 'true' if the item is a list. 630 | function isList(RLPItem memory self) internal constant returns (bool ret) { 631 | if (self._unsafe_length == 0) 632 | return false; 633 | uint memPtr = self._unsafe_memPtr; 634 | assembly { 635 | ret := iszero(lt(byte(0, mload(memPtr)), 0xC0)) 636 | } 637 | } 638 | 639 | /// @dev Check if the RLP item is data. 640 | /// @param self The RLP item. 641 | /// @return 'true' if the item is data. 642 | function isData(RLPItem memory self) internal constant returns (bool ret) { 643 | if (self._unsafe_length == 0) 644 | return false; 645 | uint memPtr = self._unsafe_memPtr; 646 | assembly { 647 | ret := lt(byte(0, mload(memPtr)), 0xC0) 648 | } 649 | } 650 | 651 | /// @dev Check if the RLP item is empty (string or list). 652 | /// @param self The RLP item. 653 | /// @return 'true' if the item is null. 654 | function isEmpty(RLPItem memory self) internal constant returns (bool ret) { 655 | if(isNull(self)) 656 | return false; 657 | uint b0; 658 | uint memPtr = self._unsafe_memPtr; 659 | assembly { 660 | b0 := byte(0, mload(memPtr)) 661 | } 662 | return (b0 == DATA_SHORT_START || b0 == LIST_SHORT_START); 663 | } 664 | 665 | /// @dev Get the number of items in an RLP encoded list. 666 | /// @param self The RLP item. 667 | /// @return The number of items. 668 | function items(RLPItem memory self) internal constant returns (uint) { 669 | if (!isList(self)) 670 | return 0; 671 | uint b0; 672 | uint memPtr = self._unsafe_memPtr; 673 | assembly { 674 | b0 := byte(0, mload(memPtr)) 675 | } 676 | uint pos = memPtr + _payloadOffset(self); 677 | uint last = memPtr + self._unsafe_length - 1; 678 | uint itms; 679 | while(pos <= last) { 680 | pos += _itemLength(pos); 681 | itms++; 682 | } 683 | return itms; 684 | } 685 | 686 | /// @dev Create an iterator. 687 | /// @param self The RLP item. 688 | /// @return An 'Iterator' over the item. 689 | function iterator(RLPItem memory self) internal constant returns (Iterator memory it) { 690 | if (!isList(self)) 691 | throw; 692 | uint ptr = self._unsafe_memPtr + _payloadOffset(self); 693 | it._unsafe_item = self; 694 | it._unsafe_nextPtr = ptr; 695 | } 696 | 697 | /// @dev Return the RLP encoded bytes. 698 | /// @param self The RLPItem. 699 | /// @return The bytes. 700 | function toBytes(RLPItem memory self) internal constant returns (bytes memory bts) { 701 | var len = self._unsafe_length; 702 | if (len == 0) 703 | return; 704 | bts = new bytes(len); 705 | _copyToBytes(self._unsafe_memPtr, bts, len); 706 | } 707 | 708 | /// @dev Decode an RLPItem into bytes. This will not work if the 709 | /// RLPItem is a list. 710 | /// @param self The RLPItem. 711 | /// @return The decoded string. 712 | function toData(RLPItem memory self) internal constant returns (bytes memory bts) { 713 | if(!isData(self)) 714 | throw; 715 | var (rStartPos, len) = _decode(self); 716 | bts = new bytes(len); 717 | _copyToBytes(rStartPos, bts, len); 718 | } 719 | 720 | /// @dev Get the list of sub-items from an RLP encoded list. 721 | /// Warning: This is inefficient, as it requires that the list is read twice. 722 | /// @param self The RLP item. 723 | /// @return Array of RLPItems. 724 | function toList(RLPItem memory self) internal constant returns (RLPItem[] memory list) { 725 | if(!isList(self)) 726 | throw; 727 | var numItems = items(self); 728 | list = new RLPItem[](numItems); 729 | var it = iterator(self); 730 | uint idx; 731 | while(hasNext(it)) { 732 | list[idx] = next(it); 733 | idx++; 734 | } 735 | } 736 | 737 | /// @dev Decode an RLPItem into an ascii string. This will not work if the 738 | /// RLPItem is a list. 739 | /// @param self The RLPItem. 740 | /// @return The decoded string. 741 | function toAscii(RLPItem memory self) internal constant returns (string memory str) { 742 | if(!isData(self)) 743 | throw; 744 | var (rStartPos, len) = _decode(self); 745 | bytes memory bts = new bytes(len); 746 | _copyToBytes(rStartPos, bts, len); 747 | str = string(bts); 748 | } 749 | 750 | /// @dev Decode an RLPItem into a uint. This will not work if the 751 | /// RLPItem is a list. 752 | /// @param self The RLPItem. 753 | /// @return The decoded string. 754 | function toUint(RLPItem memory self) internal constant returns (uint data) { 755 | if(!isData(self)) 756 | throw; 757 | var (rStartPos, len) = _decode(self); 758 | if (len > 32 || len == 0) 759 | throw; 760 | assembly { 761 | data := div(mload(rStartPos), exp(256, sub(32, len))) 762 | } 763 | } 764 | 765 | /// @dev Decode an RLPItem into a boolean. This will not work if the 766 | /// RLPItem is a list. 767 | /// @param self The RLPItem. 768 | /// @return The decoded string. 769 | function toBool(RLPItem memory self) internal constant returns (bool data) { 770 | if(!isData(self)) 771 | throw; 772 | var (rStartPos, len) = _decode(self); 773 | if (len != 1) 774 | throw; 775 | uint temp; 776 | assembly { 777 | temp := byte(0, mload(rStartPos)) 778 | } 779 | if (temp > 1) 780 | throw; 781 | return temp == 1 ? true : false; 782 | } 783 | 784 | /// @dev Decode an RLPItem into a byte. This will not work if the 785 | /// RLPItem is a list. 786 | /// @param self The RLPItem. 787 | /// @return The decoded string. 788 | function toByte(RLPItem memory self) internal constant returns (byte data) { 789 | if(!isData(self)) 790 | throw; 791 | var (rStartPos, len) = _decode(self); 792 | if (len != 1) 793 | throw; 794 | uint temp; 795 | assembly { 796 | temp := byte(0, mload(rStartPos)) 797 | } 798 | return byte(temp); 799 | } 800 | 801 | /// @dev Decode an RLPItem into an int. This will not work if the 802 | /// RLPItem is a list. 803 | /// @param self The RLPItem. 804 | /// @return The decoded string. 805 | function toInt(RLPItem memory self) internal constant returns (int data) { 806 | return int(toUint(self)); 807 | } 808 | 809 | /// @dev Decode an RLPItem into a bytes32. This will not work if the 810 | /// RLPItem is a list. 811 | /// @param self The RLPItem. 812 | /// @return The decoded string. 813 | function toBytes32(RLPItem memory self) internal constant returns (bytes32 data) { 814 | return bytes32(toUint(self)); 815 | } 816 | 817 | /// @dev Decode an RLPItem into an address. This will not work if the 818 | /// RLPItem is a list. 819 | /// @param self The RLPItem. 820 | /// @return The decoded string. 821 | function toAddress(RLPItem memory self) internal constant returns (address data) { 822 | if(!isData(self)) 823 | throw; 824 | var (rStartPos, len) = _decode(self); 825 | if (len != 20) 826 | throw; 827 | assembly { 828 | data := div(mload(rStartPos), exp(256, 12)) 829 | } 830 | } 831 | 832 | // Get the payload offset. 833 | function _payloadOffset(RLPItem memory self) private constant returns (uint) { 834 | if(self._unsafe_length == 0) 835 | return 0; 836 | uint b0; 837 | uint memPtr = self._unsafe_memPtr; 838 | assembly { 839 | b0 := byte(0, mload(memPtr)) 840 | } 841 | if(b0 < DATA_SHORT_START) 842 | return 0; 843 | if(b0 < DATA_LONG_START || (b0 >= LIST_SHORT_START && b0 < LIST_LONG_START)) 844 | return 1; 845 | if(b0 < LIST_SHORT_START) 846 | return b0 - DATA_LONG_OFFSET + 1; 847 | return b0 - LIST_LONG_OFFSET + 1; 848 | } 849 | 850 | // Get the full length of an RLP item. 851 | function _itemLength(uint memPtr) private constant returns (uint len) { 852 | uint b0; 853 | assembly { 854 | b0 := byte(0, mload(memPtr)) 855 | } 856 | if (b0 < DATA_SHORT_START) 857 | len = 1; 858 | else if (b0 < DATA_LONG_START) 859 | len = b0 - DATA_SHORT_START + 1; 860 | else if (b0 < LIST_SHORT_START) { 861 | assembly { 862 | let bLen := sub(b0, 0xB7) // bytes length (DATA_LONG_OFFSET) 863 | let dLen := div(mload(add(memPtr, 1)), exp(256, sub(32, bLen))) // data length 864 | len := add(1, add(bLen, dLen)) // total length 865 | } 866 | } 867 | else if (b0 < LIST_LONG_START) 868 | len = b0 - LIST_SHORT_START + 1; 869 | else { 870 | assembly { 871 | let bLen := sub(b0, 0xF7) // bytes length (LIST_LONG_OFFSET) 872 | let dLen := div(mload(add(memPtr, 1)), exp(256, sub(32, bLen))) // data length 873 | len := add(1, add(bLen, dLen)) // total length 874 | } 875 | } 876 | } 877 | 878 | // Get start position and length of the data. 879 | function _decode(RLPItem memory self) private constant returns (uint memPtr, uint len) { 880 | if(!isData(self)) 881 | throw; 882 | uint b0; 883 | uint start = self._unsafe_memPtr; 884 | assembly { 885 | b0 := byte(0, mload(start)) 886 | } 887 | if (b0 < DATA_SHORT_START) { 888 | memPtr = start; 889 | len = 1; 890 | return; 891 | } 892 | if (b0 < DATA_LONG_START) { 893 | len = self._unsafe_length - 1; 894 | memPtr = start + 1; 895 | } else { 896 | uint bLen; 897 | assembly { 898 | bLen := sub(b0, 0xB7) // DATA_LONG_OFFSET 899 | } 900 | len = self._unsafe_length - 1 - bLen; 901 | memPtr = start + bLen + 1; 902 | } 903 | return; 904 | } 905 | 906 | // Assumes that enough memory has been allocated to store in target. 907 | function _copyToBytes(uint btsPtr, bytes memory tgt, uint btsLen) private constant { 908 | // Exploiting the fact that 'tgt' was the last thing to be allocated, 909 | // we can write entire words, and just overwrite any excess. 910 | assembly { 911 | { 912 | let i := 0 // Start at arr + 0x20 913 | let words := div(add(btsLen, 31), 32) 914 | let rOffset := btsPtr 915 | let wOffset := add(tgt, 0x20) 916 | tag_loop: 917 | jumpi(end, eq(i, words)) 918 | { 919 | let offset := mul(i, 0x20) 920 | mstore(add(wOffset, offset), mload(add(rOffset, offset))) 921 | i := add(i, 1) 922 | } 923 | jump(tag_loop) 924 | end: 925 | mstore(add(tgt, add(0x20, mload(tgt))), 0) 926 | } 927 | } 928 | } 929 | 930 | // Check that an RLP item is valid. 931 | function _validate(RLPItem memory self) private constant returns (bool ret) { 932 | // Check that RLP is well-formed. 933 | uint b0; 934 | uint b1; 935 | uint memPtr = self._unsafe_memPtr; 936 | assembly { 937 | b0 := byte(0, mload(memPtr)) 938 | b1 := byte(1, mload(memPtr)) 939 | } 940 | if(b0 == DATA_SHORT_START + 1 && b1 < DATA_SHORT_START) 941 | return false; 942 | return true; 943 | } 944 | } 945 | 946 | 947 | contract RLPReaderTest { 948 | 949 | using RLP for RLP.RLPItem; 950 | using RLP for RLP.Iterator; 951 | using RLP for bytes; 952 | 953 | function RLPReaderTest() {} 954 | 955 | function testItemStrict(bytes rlp) constant returns (bool res) { 956 | res = true; 957 | rlp.toRLPItem(true); 958 | } 959 | 960 | function testFirst(bytes rlp) constant returns (uint memPtr, uint len, byte first) { 961 | var item = rlp.toRLPItem(); 962 | memPtr = item._unsafe_memPtr; 963 | len = item._unsafe_length; 964 | uint b0; 965 | assembly { 966 | b0 := byte(0, mload(memPtr)) 967 | } 968 | first = byte(b0); 969 | } 970 | 971 | function testIsList(bytes rlp) constant returns (bool ret) { 972 | ret = rlp.toRLPItem().isList(); 973 | } 974 | 975 | function testIsData(bytes rlp) constant returns (bool ret) { 976 | ret = rlp.toRLPItem().isData(); 977 | } 978 | 979 | function testIsNull(bytes rlp) constant returns (bool ret) { 980 | ret = rlp.toRLPItem().isNull(); 981 | } 982 | 983 | function testIsEmpty(bytes rlp) constant returns (bool ret) { 984 | ret = rlp.toRLPItem().isEmpty(); 985 | } 986 | 987 | function testItems(bytes rlp) constant returns (uint) { 988 | return rlp.toRLPItem().items(); 989 | } 990 | 991 | function testSubItem(bytes rlp, uint index) constant returns (uint memPtr, uint len, bool isList, uint[] list, uint listLen) { 992 | var it = rlp.toRLPItem().iterator(); 993 | uint idx; 994 | while(it.hasNext() && idx < index) { 995 | it.next(); 996 | idx++; 997 | } 998 | var si = it.next(); 999 | return _testItem(si); 1000 | } 1001 | 1002 | function testToData(bytes rlp) constant returns (bytes memory bts) { 1003 | bts = rlp.toRLPItem().toData(); 1004 | } 1005 | 1006 | function testToUint(bytes rlp) constant returns (uint) { 1007 | return rlp.toRLPItem().toUint(); 1008 | } 1009 | 1010 | function testToInt(bytes rlp) constant returns (int) { 1011 | return rlp.toRLPItem().toInt(); 1012 | } 1013 | 1014 | function testToBytes32(bytes rlp) constant returns (bytes32) { 1015 | return rlp.toRLPItem().toBytes32(); 1016 | } 1017 | 1018 | function testToAddress(bytes rlp) constant returns (address) { 1019 | return rlp.toRLPItem().toAddress(); 1020 | } 1021 | 1022 | function testToByte(bytes rlp) constant returns (byte) { 1023 | return rlp.toRLPItem().toByte(); 1024 | } 1025 | 1026 | function testToBool(bytes rlp) constant returns (bool) { 1027 | return rlp.toRLPItem().toBool(); 1028 | } 1029 | 1030 | function _testItem(RLP.RLPItem item) internal constant returns (uint memPtr, uint len, bool isList, uint[] memory list, uint listLen) { 1031 | memPtr = item._unsafe_memPtr; 1032 | len = item._unsafe_length; 1033 | isList = item.isList(); 1034 | 1035 | if (isList) { 1036 | uint i; 1037 | listLen = item.items(); 1038 | list = new uint[](listLen); 1039 | var it = item.iterator(); 1040 | while(it.hasNext() && i < listLen) { 1041 | var si = it.next(); 1042 | uint ptr; 1043 | assembly { 1044 | ptr := mload(si) 1045 | } 1046 | list[i] = ptr; 1047 | i++; 1048 | } 1049 | } 1050 | } 1051 | 1052 | function testItem(bytes rlp) constant returns (uint memPtr, uint len, bool isList, uint[] list, uint listLen) { 1053 | var item = rlp.toRLPItem(); 1054 | return _testItem(item); 1055 | } 1056 | 1057 | function getItem(bytes rlp, uint itemIndex) constant returns(uint) { 1058 | var it = rlp.toRLPItem().iterator(); 1059 | uint idx; 1060 | while(it.hasNext() && idx < itemIndex) { 1061 | it.next(); 1062 | idx++; 1063 | } 1064 | 1065 | 1066 | return it.next().toUint(); 1067 | } 1068 | 1069 | } 1070 | 1071 | 1072 | contract Agt { 1073 | using RLP for RLP.RLPItem; 1074 | using RLP for RLP.Iterator; 1075 | using RLP for bytes; 1076 | 1077 | struct BlockHeader { 1078 | uint prevBlockHash; // 0 1079 | uint coinbase; // 1 1080 | uint blockNumber; // 8 1081 | uint timestamp; // 11 1082 | bytes32 extraData; // 12 1083 | } 1084 | 1085 | function Agt() {} 1086 | 1087 | function parseBlockHeader( bytes rlpHeader ) constant internal returns(BlockHeader) { 1088 | BlockHeader memory header; 1089 | 1090 | var it = rlpHeader.toRLPItem().iterator(); 1091 | uint idx; 1092 | while(it.hasNext()) { 1093 | if( idx == 0 ) header.prevBlockHash = it.next().toUint(); 1094 | else if ( idx == 2 ) header.coinbase = it.next().toUint(); 1095 | else if ( idx == 8 ) header.blockNumber = it.next().toUint(); 1096 | else if ( idx == 11 ) header.timestamp = it.next().toUint(); 1097 | else if ( idx == 12 ) header.extraData = bytes32(it.next().toUint()); 1098 | else it.next(); 1099 | 1100 | idx++; 1101 | } 1102 | 1103 | return header; 1104 | } 1105 | 1106 | event VerifyAgt( string msg, uint index ); 1107 | 1108 | struct VerifyAgtData { 1109 | uint rootHash; 1110 | uint rootMin; 1111 | uint rootMax; 1112 | 1113 | uint leafHash; 1114 | uint leafCounter; 1115 | } 1116 | 1117 | function verifyAgt( /*uint[3] root, // [0] = min, [1] = max, [2] = root hash 1118 | uint[2] leafData, // [0] = hash, [1] = counter 1119 | //uint leaf32BytesHash, 1120 | //uint leafCounter,*/ 1121 | VerifyAgtData data, 1122 | uint branchIndex, 1123 | uint[] countersBranch, 1124 | uint[] hashesBranch ) constant internal returns(bool) { 1125 | 1126 | uint currentHash = data.leafHash & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 1127 | 1128 | uint leftCounterMin; 1129 | uint leftCounterMax; 1130 | uint leftHash; 1131 | 1132 | uint rightCounterMin; 1133 | uint rightCounterMax; 1134 | uint rightHash; 1135 | 1136 | uint min = data.leafCounter; 1137 | uint max = data.leafCounter; 1138 | 1139 | for( uint i = 0 ; i < countersBranch.length ; i++ ) { 1140 | if( branchIndex & 0x1 > 0 ) { 1141 | leftCounterMin = countersBranch[i] & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 1142 | leftCounterMax = countersBranch[i] >> 128; 1143 | leftHash = hashesBranch[i]; 1144 | 1145 | rightCounterMin = min; 1146 | rightCounterMax = max; 1147 | rightHash = currentHash; 1148 | } 1149 | else { 1150 | leftCounterMin = min; 1151 | leftCounterMax = max; 1152 | leftHash = currentHash; 1153 | 1154 | rightCounterMin = countersBranch[i] & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 1155 | rightCounterMax = countersBranch[i] >> 128; 1156 | rightHash = hashesBranch[i]; 1157 | } 1158 | 1159 | currentHash = uint(sha3(leftCounterMin + (leftCounterMax << 128), 1160 | leftHash, 1161 | rightCounterMin + (rightCounterMax << 128), 1162 | rightHash)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; 1163 | 1164 | if( (leftCounterMin >= leftCounterMax) || (rightCounterMin >= rightCounterMax) ) { 1165 | if( i > 0 ) { 1166 | VerifyAgt( "counters mismatch",i); 1167 | return false; 1168 | } 1169 | if( leftCounterMin > leftCounterMax ) { 1170 | VerifyAgt( "counters mismatch",i); 1171 | return false; 1172 | } 1173 | if( rightCounterMin > rightCounterMax ) { 1174 | VerifyAgt( "counters mismatch",i); 1175 | return false; 1176 | } 1177 | } 1178 | 1179 | if( leftCounterMax >= rightCounterMin ) return false; 1180 | 1181 | min = leftCounterMin; 1182 | max = rightCounterMax; 1183 | 1184 | branchIndex = branchIndex / 2; 1185 | } 1186 | 1187 | if( min != data.rootMin ) { 1188 | VerifyAgt( "min does not match root min",min); 1189 | return false; 1190 | } 1191 | if( max != data.rootMax ) { 1192 | VerifyAgt( "max does not match root max",max); 1193 | return false; 1194 | } 1195 | 1196 | if( currentHash != data.rootHash ) { 1197 | VerifyAgt( "hash does not match root hash",currentHash); 1198 | return false; 1199 | } 1200 | 1201 | return true; 1202 | } 1203 | } 1204 | 1205 | 1206 | contract TestPool is Ethash, Agt { 1207 | mapping(address=>bool) public owners; 1208 | string public version = "0.1.0"; 1209 | uint public creationBlockNumber; 1210 | 1211 | bool public newVersionReleased = false; 1212 | 1213 | struct SubmissionData { 1214 | uint numShares; 1215 | uint difficulty; 1216 | uint min; 1217 | uint max; 1218 | uint augMerkle; 1219 | uint blockNumber; 1220 | } 1221 | 1222 | struct MinerData { 1223 | bytes32 minerId; 1224 | address paymentAddress; 1225 | SubmissionData lastSubmission; 1226 | bool pendingClaim; 1227 | uint lastCounter; 1228 | } 1229 | 1230 | mapping(address=>MinerData) minersData; 1231 | mapping(bytes32=>bool) public existingIds; 1232 | 1233 | 1234 | struct EthashCacheData { 1235 | uint128 merkleRoot; 1236 | uint64 fullSizeIn128Resultion; 1237 | uint64 branchDepth; 1238 | } 1239 | 1240 | mapping(uint=>EthashCacheData) public epochData; 1241 | 1242 | event Debug( string msg ); 1243 | event ErrorLog( string msg, uint i ); 1244 | event ErrorNumber( uint msg, uint i ); 1245 | event ValidShares( address indexed miner, uint time, uint numShares, uint difficulty ); 1246 | 1247 | 1248 | function TestPool( address[3] _owners ) payable { 1249 | owners[_owners[0]] = true; 1250 | owners[_owners[1]] = true; 1251 | owners[_owners[2]] = true; 1252 | 1253 | creationBlockNumber = block.number; 1254 | } 1255 | 1256 | function declareNewerVersion() { 1257 | if( ! owners[msg.sender] ) throw; 1258 | 1259 | newVersionReleased = true; 1260 | 1261 | if( ! msg.sender.send(this.balance) ) throw; 1262 | } 1263 | 1264 | function to62Encoding( uint id, uint numChars ) constant returns(bytes32) { 1265 | if( id >= (26+26+10)**numChars ) throw; 1266 | uint result = 0; 1267 | for( uint i = 0 ; i < numChars ; i++ ) { 1268 | uint b = id % (26+26+10); 1269 | uint8 char; 1270 | if( b < 10 ) { 1271 | char = uint8(b + 0x30); // 0x30 = '0' 1272 | } 1273 | else if( b < 26 + 10 ) { 1274 | char = uint8(b + 0x61 - 10); //0x61 = 'a' 1275 | } 1276 | else { 1277 | char = uint8(b + 0x41 - 26 - 10); // 0x41 = 'A' 1278 | } 1279 | 1280 | result = (result * 256) + char; 1281 | id /= (26+26+10); 1282 | } 1283 | 1284 | return bytes32(result); 1285 | } 1286 | 1287 | event Register( address indexed sender, uint error, uint errorInfo ); 1288 | function register( address paymentAddress ) { 1289 | address minerAddress = msg.sender; 1290 | 1291 | // build id 1292 | uint id = uint(minerAddress) % (26+26+10)**11; 1293 | bytes32 minerId = to62Encoding(id,11); 1294 | 1295 | if( existingIds[minersData[minerAddress].minerId] ) { 1296 | // miner id is already in use 1297 | Register( msg.sender, 0x80000000, uint(minerId) ); 1298 | return; 1299 | } 1300 | 1301 | if( paymentAddress == address(0) ) { 1302 | // payment address is 0 1303 | Register( msg.sender, 0x80000001, uint(paymentAddress) ); 1304 | return; 1305 | } 1306 | 1307 | 1308 | // last counter is set to 0. 1309 | // It might be safer to change it to now. 1310 | //minersData[minerAddress].lastCounter = now * (2**64); 1311 | minersData[minerAddress].paymentAddress = paymentAddress; 1312 | minersData[minerAddress].minerId = minerId; 1313 | existingIds[minersData[minerAddress].minerId] = true; 1314 | 1315 | // succesful registration 1316 | Register( msg.sender, 0, 0 ); 1317 | } 1318 | 1319 | function canRegister(address sender) constant returns(bool) { 1320 | uint id = uint(sender) % (26+26+10)**11; 1321 | bytes32 expectedId = to62Encoding(id,11); 1322 | 1323 | return ! existingIds[expectedId]; 1324 | } 1325 | 1326 | function isRegistered(address sender) constant returns(bool) { 1327 | return minersData[sender].paymentAddress != address(0); 1328 | } 1329 | 1330 | function getMinerId(address sender) constant returns(bytes32) { 1331 | return minersData[sender].minerId; 1332 | } 1333 | 1334 | function getClaimSeed(address sender) constant returns(uint){ 1335 | MinerData memory data = minersData[sender]; 1336 | if( block.number > data.lastSubmission.blockNumber + 200 ) return 0; 1337 | if( block.number <= data.lastSubmission.blockNumber + 1 ) return 0; 1338 | return uint(block.blockhash(data.lastSubmission.blockNumber + 1)); 1339 | } 1340 | 1341 | event SubmitClaim( address indexed sender, uint error, uint errorInfo ); 1342 | function submitClaim( uint numShares, uint difficulty, uint min, uint max, uint augMerkle ) { 1343 | 1344 | if( ! isRegistered(msg.sender) ) { 1345 | // miner is not registered 1346 | SubmitClaim( msg.sender, 0x81000000, 0 ); 1347 | return; 1348 | } 1349 | 1350 | MinerData memory data = minersData[msg.sender]; 1351 | 1352 | if( data.lastCounter >= min ) { 1353 | // miner cheated. min counter is too low 1354 | SubmitClaim( msg.sender, 0x81000001, data.lastCounter ); 1355 | return; 1356 | } 1357 | 1358 | MinerData memory newData = data; 1359 | 1360 | newData.lastCounter = max; 1361 | 1362 | newData.lastSubmission.numShares = numShares; 1363 | newData.lastSubmission.difficulty = difficulty; 1364 | newData.lastSubmission.min = min; 1365 | newData.lastSubmission.max = max; 1366 | newData.lastSubmission.augMerkle = augMerkle; 1367 | newData.lastSubmission.blockNumber = block.number; 1368 | newData.pendingClaim = true; 1369 | 1370 | minersData[msg.sender] = newData; 1371 | 1372 | // everything is ok 1373 | SubmitClaim( msg.sender, 0, 0 ); 1374 | } 1375 | 1376 | event SetEpochData( address indexed sender, uint error, uint errorInfo ); 1377 | function setEpochData( uint128[] merkleRoot, uint64[] fullSizeIn128Resultion, uint64[] branchDepth, uint[] epoch ) { 1378 | EthashCacheData memory data; 1379 | 1380 | if( ! owners[msg.sender] ) { 1381 | //ErrorLog( "setEpochData: only owner can set data", uint(msg.sender) ); 1382 | SetEpochData( msg.sender, 0x82000000, uint(msg.sender) ); 1383 | return; 1384 | } 1385 | 1386 | for( uint i = 0 ; i < epoch.length ; i++ ) { 1387 | data.merkleRoot = merkleRoot[i]; 1388 | data.fullSizeIn128Resultion = fullSizeIn128Resultion[i]; 1389 | data.branchDepth = branchDepth[i]; 1390 | 1391 | if( epochData[epoch[i]].merkleRoot > 0 ) { 1392 | //ErrorLog("epoch already set", epoch[i]); 1393 | SetEpochData( msg.sender, 0x82000001, epoch[i] ); 1394 | continue; 1395 | } 1396 | 1397 | epochData[epoch[i]] = data; 1398 | } 1399 | 1400 | SetEpochData( msg.sender, 0, 0 ); 1401 | } 1402 | 1403 | function getEpochData( uint epoch ) constant returns(uint[3]) { 1404 | return [uint(epochData[epoch].merkleRoot), 1405 | uint(epochData[epoch].fullSizeIn128Resultion), 1406 | uint(epochData[epoch].branchDepth)]; 1407 | } 1408 | 1409 | event VerifyExtraData( address indexed sender, uint error, uint errorInfo ); 1410 | function verifyExtraData( bytes32 extraData, bytes32 minerId, uint difficulty ) constant internal returns(bool) { 1411 | uint i; 1412 | // compare id 1413 | for( i = 0 ; i < 11 ; i++ ) { 1414 | if( extraData[10+i] != minerId[21+i] ) { 1415 | //ErrorLog( "verifyExtraData: miner id not as expected", 0 ); 1416 | VerifyExtraData( msg.sender, 0x83000000, uint(minerId) ); 1417 | return false; 1418 | } 1419 | } 1420 | 1421 | // compare difficulty 1422 | bytes32 encodedDiff = to62Encoding(difficulty,11); 1423 | for( i = 0 ; i < 11 ; i++ ) { 1424 | if(extraData[i+21] != encodedDiff[21+i]) { 1425 | //ErrorLog( "verifyExtraData: difficulty is not as expected", uint(encodedDiff) ); 1426 | VerifyExtraData( msg.sender, 0x83000001, uint(encodedDiff) ); 1427 | return false; 1428 | } 1429 | } 1430 | 1431 | return true; 1432 | } 1433 | 1434 | event VerifyClaim( address indexed sender, uint error, uint errorInfo ); 1435 | 1436 | 1437 | function verifyClaim( bytes rlpHeader, 1438 | uint nonce, 1439 | uint shareIndex, 1440 | uint[] dataSetLookup, 1441 | uint[] witnessForLookup, 1442 | uint[] augCountersBranch, 1443 | uint[] augHashesBranch ) returns(uint) { 1444 | 1445 | BlockHeader memory header = parseBlockHeader(rlpHeader); 1446 | SubmissionData memory submissionData = minersData[ msg.sender ].lastSubmission; 1447 | 1448 | if( getClaimSeed(msg.sender) == 0 ) { 1449 | //ErrorLog( "claim seed is 0", 0 ); 1450 | VerifyClaim( msg.sender, 0x84000001, 0 ); 1451 | return 289; 1452 | } 1453 | 1454 | if( shareIndex != getShareIndex(msg.sender) ) { 1455 | //ErrorLog( "share index is not as expected. should be:", getShareIndex() ); 1456 | VerifyClaim( msg.sender, 0x84000002, getShareIndex(msg.sender) ); 1457 | return 589; 1458 | } 1459 | 1460 | if( ! minersData[ msg.sender ].pendingClaim ) { 1461 | //ErrorLog( "there are no pending claims", 0 ); 1462 | VerifyClaim( msg.sender, 0x84000003, 0 ); 1463 | return 189; 1464 | } 1465 | 1466 | // check extra data 1467 | if( ! verifyExtraData( header.extraData, 1468 | minersData[ msg.sender ].minerId, 1469 | submissionData.difficulty ) ) { 1470 | //ErrorLog( "extra data not as expected", uint(header.extraData) ); 1471 | VerifyClaim( msg.sender, 0x84000004, uint(header.extraData) ); 1472 | return 2; 1473 | } 1474 | 1475 | // check coinbase data 1476 | if( header.coinbase != uint(this) ) { 1477 | //ErrorLog( "coinbase not as expected", uint(header.coinbase) ); 1478 | VerifyClaim( msg.sender, 0x84000005, uint(header.coinbase) ); 1479 | return 3; 1480 | } 1481 | 1482 | 1483 | // check counter 1484 | uint counter = header.timestamp * (2 ** 64) + nonce; 1485 | if( counter < submissionData.min ) { 1486 | //ErrorLog( "counter is smaller than min",counter); 1487 | ErrorNumber( 0x8000000c, counter ); 1488 | VerifyClaim( msg.sender, 0x84000007, counter ); 1489 | return 4; 1490 | } 1491 | if( counter > submissionData.max ) { 1492 | //ErrorLog( "counter is smaller than max",counter); 1493 | VerifyClaim( msg.sender, 0x84000008, counter ); 1494 | return 5; 1495 | } 1496 | 1497 | // verify agt 1498 | uint leafHash = uint(sha3(rlpHeader)); 1499 | VerifyAgtData memory agtData; 1500 | agtData.rootHash = submissionData.augMerkle; 1501 | agtData.rootMin = submissionData.min; 1502 | agtData.rootMax = submissionData.max; 1503 | agtData.leafHash = leafHash; 1504 | agtData.leafCounter = counter; 1505 | 1506 | 1507 | if( ! verifyAgt( agtData, 1508 | shareIndex, 1509 | augCountersBranch, 1510 | augHashesBranch ) ) { 1511 | //ErrorLog( "verifyAgt failed",0); 1512 | VerifyClaim( msg.sender, 0x84000009, 0 ); 1513 | return 6; 1514 | } 1515 | 1516 | 1517 | // get epoch data 1518 | EthashCacheData memory eData = epochData[header.blockNumber / 30000]; 1519 | if( eData.merkleRoot == 0 ) { 1520 | //ErrorLog( "epoch data was not set",header.blockNumber / 30000); 1521 | VerifyClaim( msg.sender, 0x8400000a, header.blockNumber / 30000 ); 1522 | return 77; 1523 | } 1524 | 1525 | // verify ethash 1526 | uint ethash = hashimoto( bytes32(leafHash), 1527 | bytes8(nonce), 1528 | eData.fullSizeIn128Resultion, 1529 | dataSetLookup, 1530 | witnessForLookup, 1531 | eData.branchDepth, 1532 | eData.merkleRoot ); 1533 | if( ethash > ((2**256-1)/submissionData.difficulty )) { 1534 | //ErrorLog( "ethash difficulty too low",ethash); 1535 | VerifyClaim( msg.sender, 0x8400000b, ethash ); 1536 | return 7; 1537 | } 1538 | 1539 | minersData[ msg.sender ].pendingClaim = false; 1540 | 1541 | if( ! doPayment(submissionData.numShares, submissionData.difficulty, minersData[ msg.sender ].paymentAddress) ) { 1542 | // error msg is given in doPayment function 1543 | return 19; 1544 | } 1545 | ValidShares( msg.sender, now, submissionData.numShares, submissionData.difficulty ); 1546 | VerifyClaim( msg.sender, 0, 0 ); 1547 | 1548 | 1549 | return 8; 1550 | } 1551 | 1552 | 1553 | 1554 | function getShareIndex(address sender) constant returns(uint) { 1555 | SubmissionData submissionData = minersData[ sender ].lastSubmission; 1556 | return (getClaimSeed(sender) % submissionData.numShares); 1557 | } 1558 | 1559 | 1560 | uint public extraBalance; 1561 | uint public subsidyFactor = 2; 1562 | 1563 | 1564 | function() payable { 1565 | extraBalance += msg.value; 1566 | } 1567 | 1568 | function setSubsidy( uint factor ) { 1569 | if( ! owners[msg.sender] ) throw; 1570 | if( factor < 1 ) throw; 1571 | 1572 | subsidyFactor = factor; 1573 | } 1574 | 1575 | function doPayment( uint numShares, uint difficulty, address paymentAddress ) internal returns(bool) { 1576 | 1577 | uint blockDifficulty; 1578 | if( block.difficulty > 0 ) { 1579 | blockDifficulty = block.difficulty; 1580 | } 1581 | else { // testrpc 1582 | blockDifficulty = 100000; 1583 | } 1584 | 1585 | uint payment = (5 ether * difficulty * numShares / blockDifficulty); 1586 | 1587 | if( payment > this.balance ){ 1588 | //ErrorLog( "cannot afford to pay", calcPayment( submissionData.numShares, submissionData.difficulty ) ); 1589 | VerifyClaim( msg.sender, 0x84000000, payment ); 1590 | return false; 1591 | } 1592 | 1593 | uint extraPayment = payment * ( subsidyFactor-1 ); 1594 | if( ( extraPayment > extraBalance ) || (payment + extraPayment) > this.balance ) { 1595 | extraPayment = 0; 1596 | } 1597 | 1598 | extraBalance -= extraPayment; 1599 | payment += extraPayment; 1600 | 1601 | if( ! paymentAddress.send( payment ) ) throw; 1602 | 1603 | return true; 1604 | } 1605 | } 1606 | 1607 | 1608 | 1609 | --------------------------------------------------------------------------------