@ -26,8 +26,10 @@ import org.hyperledger.besu.util.Subscribers;
import java.util.Arrays ;
import java.util.List ;
import java.util.Optional ;
import java.util.concurrent.CompletableFuture ;
import java.util.concurrent.ExecutionException ;
import java.util.concurrent.TimeUnit ;
import java.util.concurrent.TimeoutException ;
import com.google.common.base.Stopwatch ;
import com.google.common.collect.Lists ;
@ -47,7 +49,8 @@ public class PoWSolverTest {
PoWHasher . ETHASH_LIGHT ,
false ,
Subscribers . none ( ) ,
new EpochCalculator . DefaultEpochCalculator ( ) ) ;
new EpochCalculator . DefaultEpochCalculator ( ) ,
1000 ) ;
assertThat ( solver . hashesPerSecond ( ) ) . isEqualTo ( Optional . empty ( ) ) ;
assertThat ( solver . getWorkDefinition ( ) ) . isEqualTo ( Optional . empty ( ) ) ;
@ -80,7 +83,8 @@ public class PoWSolverTest {
hasher ,
false ,
Subscribers . none ( ) ,
new EpochCalculator . DefaultEpochCalculator ( ) ) ;
new EpochCalculator . DefaultEpochCalculator ( ) ,
1000 ) ;
final Stopwatch operationTimer = Stopwatch . createStarted ( ) ;
final PoWSolverInputs inputs = new PoWSolverInputs ( UInt256 . ONE , Bytes . EMPTY , 5 ) ;
@ -145,7 +149,8 @@ public class PoWSolverTest {
PoWHasher . ETHASH_LIGHT ,
false ,
Subscribers . none ( ) ,
new EpochCalculator . DefaultEpochCalculator ( ) ) ;
new EpochCalculator . DefaultEpochCalculator ( ) ,
1000 ) ;
PoWSolution soln = solver . solveFor ( PoWSolver . PoWSolverJob . createFromInputs ( firstInputs ) ) ;
assertThat ( soln . getMixHash ( ) ) . isEqualTo ( expectedFirstOutput . getMixHash ( ) ) ;
@ -153,4 +158,356 @@ public class PoWSolverTest {
soln = solver . solveFor ( PoWSolver . PoWSolverJob . createFromInputs ( secondInputs ) ) ;
assertThat ( soln . getMixHash ( ) ) . isEqualTo ( expectedSecondOutput . getMixHash ( ) ) ;
}
@Test
public void canAcceptSolutionsSerially ( )
throws InterruptedException , ExecutionException , TimeoutException {
final PoWSolverInputs firstInputs =
new PoWSolverInputs (
UInt256 . fromHexString (
"0x0083126e978d4fdf3b645a1cac083126e978d4fdf3b645a1cac083126e978d4f" ) ,
Bytes . wrap (
new byte [ ] {
15 , - 114 , - 104 , 87 , - 95 , - 36 , - 17 , 120 , 52 , 1 , 124 , 61 , - 6 , - 66 , 78 , - 27 , - 57 ,
118 , - 18 , - 64 , - 103 , - 91 , - 74 , - 121 , 42 , 91 , - 14 , - 98 , 101 , 86 , - 43 , - 51
} ) ,
1 ) ;
final PoWSolution expectedFirstOutput =
new PoWSolution (
- 6506032554016940193L ,
Hash . fromHexString (
"0xc5e3c33c86d64d0641dd3c86e8ce4628fe0aac0ef7b4c087c5fcaa45d5046d90" ) ,
null ,
firstInputs . getPrePowHash ( ) ) ;
final PoWSolverInputs secondInputs =
new PoWSolverInputs (
UInt256 . fromHexString (
"0x0083126e978d4fdf3b645a1cac083126e978d4fdf3b645a1cac083126e978d4f" ) ,
Bytes . wrap (
new byte [ ] {
- 62 , 121 , - 81 , - 31 , 55 , - 38 , - 68 , 102 , - 32 , 95 , - 94 , - 83 , - 3 , - 48 , - 122 , - 68 , 14 ,
- 125 , - 83 , 84 , - 55 , - 23 , - 123 , - 57 , - 34 , 25 , - 89 , 23 , 64 , - 9 , - 114 , - 3 ,
} ) ,
2 ) ;
final PoWSolution expectedSecondOutput =
new PoWSolution (
8855952212886464488L ,
Hash . fromHexString (
"0x2adb0f375dd2d528689cb9e00473c3c9692737109d547130feafbefb2c6c5244" ) ,
null ,
secondInputs . getPrePowHash ( ) ) ;
// Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver.
final PoWSolver solver =
new PoWSolver (
Lists . newArrayList ( expectedFirstOutput . getNonce ( ) , 0L , expectedSecondOutput . getNonce ( ) ) ,
PoWHasher . ETHASH_LIGHT ,
true ,
Subscribers . none ( ) ,
new EpochCalculator . DefaultEpochCalculator ( ) ,
1000 ) ;
CompletableFuture < PoWSolution > soln1 = new CompletableFuture < > ( ) ;
CompletableFuture < PoWSolution > soln2 = new CompletableFuture < > ( ) ;
Thread powThread =
new Thread (
( ) - > {
try {
soln1 . complete (
solver . solveFor ( PoWSolver . PoWSolverJob . createFromInputs ( firstInputs ) ) ) ;
soln2 . complete (
solver . solveFor ( PoWSolver . PoWSolverJob . createFromInputs ( secondInputs ) ) ) ;
} catch ( Exception e ) {
soln1 . completeExceptionally ( e ) ;
soln2 . completeExceptionally ( e ) ;
}
} ) ;
powThread . start ( ) ;
Thread . sleep ( 200 ) ;
assertThat ( solver . submitSolution ( expectedFirstOutput ) ) . isTrue ( ) ;
Thread . sleep ( 200 ) ;
assertThat ( solver . submitSolution ( expectedSecondOutput ) ) . isTrue ( ) ;
PoWSolution result1 = soln1 . get ( 1 , TimeUnit . SECONDS ) ;
PoWSolution result2 = soln2 . get ( 1 , TimeUnit . SECONDS ) ;
assertThat ( result1 . getMixHash ( ) ) . isEqualTo ( expectedFirstOutput . getMixHash ( ) ) ;
assertThat ( result2 . getMixHash ( ) ) . isEqualTo ( expectedSecondOutput . getMixHash ( ) ) ;
}
@Test
public void canAcceptSolutionsForMultipleJobs ( )
throws InterruptedException , ExecutionException , TimeoutException {
final PoWSolverInputs firstInputs =
new PoWSolverInputs (
UInt256 . fromHexString (
"0x0083126e978d4fdf3b645a1cac083126e978d4fdf3b645a1cac083126e978d4f" ) ,
Bytes . wrap (
new byte [ ] {
15 , - 114 , - 104 , 87 , - 95 , - 36 , - 17 , 120 , 52 , 1 , 124 , 61 , - 6 , - 66 , 78 , - 27 , - 57 ,
118 , - 18 , - 64 , - 103 , - 91 , - 74 , - 121 , 42 , 91 , - 14 , - 98 , 101 , 86 , - 43 , - 51
} ) ,
1 ) ;
final PoWSolution expectedFirstOutput =
new PoWSolution (
- 6506032554016940193L ,
Hash . fromHexString (
"0xc5e3c33c86d64d0641dd3c86e8ce4628fe0aac0ef7b4c087c5fcaa45d5046d90" ) ,
null ,
firstInputs . getPrePowHash ( ) ) ;
final PoWSolverInputs secondInputs =
new PoWSolverInputs (
UInt256 . fromHexString (
"0x0083126e978d4fdf3b645a1cac083126e978d4fdf3b645a1cac083126e978d4f" ) ,
Bytes . wrap (
new byte [ ] {
- 62 , 121 , - 81 , - 31 , 55 , - 38 , - 68 , 102 , - 32 , 95 , - 94 , - 83 , - 3 , - 48 , - 122 , - 68 , 14 ,
- 125 , - 83 , 84 , - 55 , - 23 , - 123 , - 57 , - 34 , 25 , - 89 , 23 , 64 , - 9 , - 114 , - 3 ,
} ) ,
2 ) ;
final PoWSolution expectedSecondOutput =
new PoWSolution (
8855952212886464488L ,
Hash . fromHexString (
"0x2adb0f375dd2d528689cb9e00473c3c9692737109d547130feafbefb2c6c5244" ) ,
null ,
secondInputs . getPrePowHash ( ) ) ;
// Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver.
final PoWSolver solver =
new PoWSolver (
Lists . newArrayList ( expectedFirstOutput . getNonce ( ) , 0L , expectedSecondOutput . getNonce ( ) ) ,
PoWHasher . ETHASH_LIGHT ,
true ,
Subscribers . none ( ) ,
new EpochCalculator . DefaultEpochCalculator ( ) ,
1000 ) ;
CompletableFuture < PoWSolution > soln1 = new CompletableFuture < > ( ) ;
CompletableFuture < PoWSolution > soln2 = new CompletableFuture < > ( ) ;
Thread powThread1 =
new Thread (
( ) - > {
try {
soln1 . complete (
solver . solveFor ( PoWSolver . PoWSolverJob . createFromInputs ( firstInputs ) ) ) ;
} catch ( Exception e ) {
soln1 . completeExceptionally ( e ) ;
soln2 . completeExceptionally ( e ) ;
}
} ) ;
powThread1 . start ( ) ;
Thread powThread2 =
new Thread (
( ) - > {
try {
soln2 . complete (
solver . solveFor ( PoWSolver . PoWSolverJob . createFromInputs ( secondInputs ) ) ) ;
} catch ( Exception e ) {
soln1 . completeExceptionally ( e ) ;
soln2 . completeExceptionally ( e ) ;
}
} ) ;
powThread2 . start ( ) ;
Thread . sleep ( 200 ) ;
assertThat ( solver . submitSolution ( expectedFirstOutput ) ) . isTrue ( ) ;
Thread . sleep ( 200 ) ;
assertThat ( solver . submitSolution ( expectedSecondOutput ) ) . isTrue ( ) ;
PoWSolution result1 = soln1 . get ( 1 , TimeUnit . SECONDS ) ;
PoWSolution result2 = soln2 . get ( 1 , TimeUnit . SECONDS ) ;
assertThat ( result1 . getMixHash ( ) ) . isEqualTo ( expectedFirstOutput . getMixHash ( ) ) ;
assertThat ( result2 . getMixHash ( ) ) . isEqualTo ( expectedSecondOutput . getMixHash ( ) ) ;
}
@Test
public void canAcceptAtMostOneSolution ( )
throws InterruptedException , ExecutionException , TimeoutException {
final PoWSolverInputs firstInputs =
new PoWSolverInputs (
UInt256 . fromHexString (
"0x0083126e978d4fdf3b645a1cac083126e978d4fdf3b645a1cac083126e978d4f" ) ,
Bytes . wrap (
new byte [ ] {
15 , - 114 , - 104 , 87 , - 95 , - 36 , - 17 , 120 , 52 , 1 , 124 , 61 , - 6 , - 66 , 78 , - 27 , - 57 ,
118 , - 18 , - 64 , - 103 , - 91 , - 74 , - 121 , 42 , 91 , - 14 , - 98 , 101 , 86 , - 43 , - 51
} ) ,
1 ) ;
final PoWSolution expectedFirstOutput =
new PoWSolution (
- 6506032554016940193L ,
Hash . fromHexString (
"0xc5e3c33c86d64d0641dd3c86e8ce4628fe0aac0ef7b4c087c5fcaa45d5046d90" ) ,
null ,
firstInputs . getPrePowHash ( ) ) ;
final PoWSolverInputs secondInputs =
new PoWSolverInputs (
UInt256 . fromHexString (
"0x0083126e978d4fdf3b645a1cac083126e978d4fdf3b645a1cac083126e978d4f" ) ,
Bytes . wrap (
new byte [ ] {
- 62 , 121 , - 81 , - 31 , 55 , - 38 , - 68 , 102 , - 32 , 95 , - 94 , - 83 , - 3 , - 48 , - 122 , - 68 , 14 ,
- 125 , - 83 , 84 , - 55 , - 23 , - 123 , - 57 , - 34 , 25 , - 89 , 23 , 64 , - 9 , - 114 , - 3 ,
} ) ,
2 ) ;
final PoWSolution expectedSecondOutput =
new PoWSolution (
8855952212886464488L ,
Hash . fromHexString (
"0x2adb0f375dd2d528689cb9e00473c3c9692737109d547130feafbefb2c6c5244" ) ,
null ,
secondInputs . getPrePowHash ( ) ) ;
// Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver.
final PoWSolver solver =
new PoWSolver (
Lists . newArrayList ( expectedFirstOutput . getNonce ( ) , 0L , expectedSecondOutput . getNonce ( ) ) ,
PoWHasher . ETHASH_LIGHT ,
true ,
Subscribers . none ( ) ,
new EpochCalculator . DefaultEpochCalculator ( ) ,
1000 ) ;
CompletableFuture < PoWSolution > soln1 = new CompletableFuture < > ( ) ;
CompletableFuture < PoWSolution > soln2 = new CompletableFuture < > ( ) ;
Thread powThread1 =
new Thread (
( ) - > {
try {
soln1 . complete (
solver . solveFor ( PoWSolver . PoWSolverJob . createFromInputs ( firstInputs ) ) ) ;
} catch ( Exception e ) {
soln1 . completeExceptionally ( e ) ;
soln2 . completeExceptionally ( e ) ;
}
} ) ;
powThread1 . start ( ) ;
Thread powThread2 =
new Thread (
( ) - > {
try {
soln2 . complete (
solver . solveFor ( PoWSolver . PoWSolverJob . createFromInputs ( secondInputs ) ) ) ;
} catch ( Exception e ) {
soln1 . completeExceptionally ( e ) ;
soln2 . completeExceptionally ( e ) ;
}
} ) ;
powThread2 . start ( ) ;
Thread . sleep ( 200 ) ;
assertThat ( solver . submitSolution ( expectedFirstOutput ) ) . isTrue ( ) ;
Thread . sleep ( 200 ) ;
assertThat ( solver . submitSolution ( expectedSecondOutput ) ) . isTrue ( ) ;
assertThat ( solver . submitSolution ( expectedSecondOutput ) ) . isFalse ( ) ;
assertThat ( solver . submitSolution ( expectedFirstOutput ) ) . isFalse ( ) ;
PoWSolution result1 = soln1 . get ( 1 , TimeUnit . SECONDS ) ;
PoWSolution result2 = soln2 . get ( 1 , TimeUnit . SECONDS ) ;
assertThat ( result1 . getMixHash ( ) ) . isEqualTo ( expectedFirstOutput . getMixHash ( ) ) ;
assertThat ( result2 . getMixHash ( ) ) . isEqualTo ( expectedSecondOutput . getMixHash ( ) ) ;
}
@Test
public void rejectsSolutionsForOldBlocks ( )
throws InterruptedException , ExecutionException , TimeoutException {
final PoWSolverInputs firstInputs =
new PoWSolverInputs (
UInt256 . fromHexString (
"0x0083126e978d4fdf3b645a1cac083126e978d4fdf3b645a1cac083126e978d4f" ) ,
Bytes . wrap (
new byte [ ] {
15 , - 114 , - 104 , 87 , - 95 , - 36 , - 17 , 120 , 52 , 1 , 124 , 61 , - 6 , - 66 , 78 , - 27 , - 57 ,
118 , - 18 , - 64 , - 103 , - 91 , - 74 , - 121 , 42 , 91 , - 14 , - 98 , 101 , 86 , - 43 , - 51
} ) ,
1 ) ;
final PoWSolution expectedFirstOutput =
new PoWSolution (
- 6506032554016940193L ,
Hash . fromHexString (
"0xc5e3c33c86d64d0641dd3c86e8ce4628fe0aac0ef7b4c087c5fcaa45d5046d90" ) ,
null ,
firstInputs . getPrePowHash ( ) ) ;
final PoWSolverInputs secondInputs =
new PoWSolverInputs (
UInt256 . fromHexString (
"0x0083126e978d4fdf3b645a1cac083126e978d4fdf3b645a1cac083126e978d4f" ) ,
Bytes . wrap (
new byte [ ] {
- 62 , 121 , - 81 , - 31 , 55 , - 38 , - 68 , 102 , - 32 , 95 , - 94 , - 83 , - 3 , - 48 , - 122 , - 68 , 14 ,
- 125 , - 83 , 84 , - 55 , - 23 , - 123 , - 57 , - 34 , 25 , - 89 , 23 , 64 , - 9 , - 114 , - 3 ,
} ) ,
10 ) ;
final PoWSolution expectedSecondOutput =
new PoWSolution (
8855952212886464488L ,
Hash . fromHexString (
"0x2adb0f375dd2d528689cb9e00473c3c9692737109d547130feafbefb2c6c5244" ) ,
null ,
secondInputs . getPrePowHash ( ) ) ;
// Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver.
final PoWSolver solver =
new PoWSolver (
Lists . newArrayList ( expectedFirstOutput . getNonce ( ) , 0L , expectedSecondOutput . getNonce ( ) ) ,
PoWHasher . ETHASH_LIGHT ,
true ,
Subscribers . none ( ) ,
new EpochCalculator . DefaultEpochCalculator ( ) ,
1000 ) ;
CompletableFuture < PoWSolution > soln1 = new CompletableFuture < > ( ) ;
CompletableFuture < PoWSolution > soln2 = new CompletableFuture < > ( ) ;
Thread powThread1 =
new Thread (
( ) - > {
try {
soln1 . complete (
solver . solveFor ( PoWSolver . PoWSolverJob . createFromInputs ( firstInputs ) ) ) ;
} catch ( Exception e ) {
soln1 . completeExceptionally ( e ) ;
}
} ) ;
powThread1 . start ( ) ;
Thread . sleep ( 200 ) ;
Thread powThread2 =
new Thread (
( ) - > {
try {
soln2 . complete (
solver . solveFor ( PoWSolver . PoWSolverJob . createFromInputs ( secondInputs ) ) ) ;
} catch ( Exception e ) {
soln2 . completeExceptionally ( e ) ;
}
} ) ;
powThread2 . start ( ) ;
Thread . sleep ( 200 ) ;
// we solve the head job, and still keep it as our reference as the block with the highest
// number.
assertThat ( solver . submitSolution ( expectedSecondOutput ) ) . isTrue ( ) ;
Thread . sleep ( 200 ) ;
assertThat ( solver . submitSolution ( expectedFirstOutput ) ) . isFalse ( ) ;
PoWSolution result2 = soln2 . get ( 1 , TimeUnit . SECONDS ) ;
assertThat ( result2 . getMixHash ( ) ) . isEqualTo ( expectedSecondOutput . getMixHash ( ) ) ;
powThread1 . interrupt ( ) ;
}
}