Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
T
teku
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
teku
Commits
fbccbf30
Commit
fbccbf30
authored
Jul 19, 2025
by
luxq
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add new inject point
parent
c49b35d6
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
356 additions
and
192 deletions
+356
-192
build.gradle
attacker/client/build.gradle
+1
-4
AttackService.java
...c/main/java/tech/pegasys/teku/attacker/AttackService.java
+112
-84
JsonRpcClientUtil.java
...in/java/tech/pegasys/teku/attacker/JsonRpcClientUtil.java
+43
-31
AttackServiceTest.java
...st/java/tech/pegasys/teku/attacker/AttackServiceTest.java
+72
-59
build.gradle
beacon/validator/build.gradle
+1
-0
ValidatorApiHandler.java
...gasys/teku/validator/coordinator/ValidatorApiHandler.java
+58
-1
build.gradle
ethereum/statetransition/build.gradle
+1
-0
BlockManager.java
...tech/pegasys/teku/statetransition/block/BlockManager.java
+55
-0
BlockProductionDuty.java
...sys/teku/validator/client/duties/BlockProductionDuty.java
+2
-2
BlockContainerSignerDeneb.java
...ku/validator/client/signer/BlockContainerSignerDeneb.java
+11
-11
No files found.
attacker/client/build.gradle
View file @
fbccbf30
repositories
{
mavenCentral
()
// Ensure Maven Central is included
}
jar
{
enabled
=
false
}
dependencies
{
implementation
project
(
':infrastructure:async'
)
implementation
'com.github.briandilley.jsonrpc4j:jsonrpc4j:1.7'
...
...
attacker/client/src/main/java/tech/pegasys/teku/attacker/AttackService.java
View file @
fbccbf30
/*
* Copyright Consensys Software Inc., 2025
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package
tech
.
pegasys
.
teku
.
attacker
;
import
com.googlecode.jsonrpc4j.JsonRpcHttpClient
;
...
...
@@ -5,87 +18,102 @@ import tech.pegasys.teku.infrastructure.async.SafeFuture;
public
class
AttackService
{
private
static
final
String
BLOCK_MODULE
=
"block"
;
private
static
final
String
ATTEST_MODULE
=
"attest"
;
private
final
JsonRpcHttpClient
jsonRpcClient
;
public
AttackService
()
{
this
.
jsonRpcClient
=
JsonRpcClientUtil
.
getInstance
().
getJsonRpcClient
();
}
public
AttackService
(
final
String
url
)
{
this
.
jsonRpcClient
=
JsonRpcClientUtil
.
getInstance
().
getJsonRpcClientByUrl
(
url
);
}
public
boolean
enabled
()
{
return
this
.
jsonRpcClient
!=
null
;
}
private
SafeFuture
<
AttackerResponse
>
invokeRpc
(
final
String
method
,
final
Object
[]
params
)
{
try
{
AttackerResponse
response
=
jsonRpcClient
.
invoke
(
method
,
params
,
AttackerResponse
.
class
);
return
SafeFuture
.
completedFuture
(
response
);
}
catch
(
Exception
e
)
{
return
SafeFuture
.
failedFuture
(
e
);
}
catch
(
Throwable
e
)
{
throw
new
RuntimeException
(
e
);
}
}
public
SafeFuture
<
AttackerResponse
>
blockGetNewParentRoot
(
final
long
slot
,
final
String
pubkey
,
final
String
parentRoot
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_getNewParentRoot"
,
new
Object
[]{
slot
,
pubkey
,
parentRoot
});
}
public
SafeFuture
<
AttackerResponse
>
delayForReceiveBlock
(
final
long
slot
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_delayForReceiveBlock"
,
new
Object
[]{
slot
});
}
public
SafeFuture
<
AttackerResponse
>
blockBeforeBroadcast
(
final
long
slot
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_beforeBroadCast"
,
new
Object
[]{
slot
});
}
public
SafeFuture
<
AttackerResponse
>
blockAfterBroadcast
(
final
long
slot
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_afterBroadCast"
,
new
Object
[]{
slot
});
}
public
SafeFuture
<
AttackerResponse
>
blockBeforeSign
(
final
long
slot
,
final
String
pubkey
,
final
String
blockDataBase64
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_beforeSign"
,
new
Object
[]{
slot
,
pubkey
,
blockDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
blockAfterSign
(
final
long
slot
,
final
String
pubkey
,
final
String
signedBlockDataBase64
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_afterSign"
,
new
Object
[]{
slot
,
pubkey
,
signedBlockDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
blockBeforePropose
(
final
long
slot
,
final
String
pubkey
,
final
String
signedBlockDataBase64
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_beforePropose"
,
new
Object
[]{
slot
,
pubkey
,
signedBlockDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
blockAfterPropose
(
final
long
slot
,
final
String
pubkey
,
final
String
signedBlockDataBase64
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_afterPropose"
,
new
Object
[]{
slot
,
pubkey
,
signedBlockDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
attestBeforeBroadcast
(
final
long
slot
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_beforeBroadCast"
,
new
Object
[]{
slot
});
}
public
SafeFuture
<
AttackerResponse
>
attestAfterBroadcast
(
final
long
slot
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_afterBroadCast"
,
new
Object
[]{
slot
});
}
public
SafeFuture
<
AttackerResponse
>
attestBeforeSign
(
final
long
slot
,
final
String
pubkey
,
final
String
attestDataBase64
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_beforeSign"
,
new
Object
[]{
slot
,
pubkey
,
attestDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
attestAfterSign
(
final
long
slot
,
final
String
pubkey
,
final
String
signedAttestDataBase64
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_afterSign"
,
new
Object
[]{
slot
,
pubkey
,
signedAttestDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
attestBeforePropose
(
final
long
slot
,
final
String
pubkey
,
final
String
signedAttestDataBase64
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_beforePropose"
,
new
Object
[]{
slot
,
pubkey
,
signedAttestDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
attestAfterPropose
(
final
long
slot
,
final
String
pubkey
,
final
String
signedAttestDataBase64
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_afterPropose"
,
new
Object
[]{
slot
,
pubkey
,
signedAttestDataBase64
});
}
}
\ No newline at end of file
private
static
final
String
BLOCK_MODULE
=
"block"
;
private
static
final
String
ATTEST_MODULE
=
"attest"
;
private
final
JsonRpcHttpClient
jsonRpcClient
;
public
AttackService
()
{
this
.
jsonRpcClient
=
JsonRpcClientUtil
.
getInstance
().
getJsonRpcClient
();
}
public
AttackService
(
final
String
url
)
{
this
.
jsonRpcClient
=
JsonRpcClientUtil
.
getInstance
().
getJsonRpcClientByUrl
(
url
);
}
public
boolean
enabled
()
{
return
this
.
jsonRpcClient
!=
null
;
}
private
SafeFuture
<
AttackerResponse
>
invokeRpc
(
final
String
method
,
final
Object
[]
params
)
{
try
{
AttackerResponse
response
=
jsonRpcClient
.
invoke
(
method
,
params
,
AttackerResponse
.
class
);
return
SafeFuture
.
completedFuture
(
response
);
}
catch
(
Exception
e
)
{
return
SafeFuture
.
failedFuture
(
e
);
}
catch
(
Throwable
e
)
{
throw
new
RuntimeException
(
e
);
}
}
public
SafeFuture
<
AttackerResponse
>
blockGetNewParentRoot
(
final
long
slot
,
final
String
pubkey
,
final
String
parentRoot
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_getNewParentRoot"
,
new
Object
[]
{
slot
,
pubkey
,
parentRoot
});
}
public
SafeFuture
<
AttackerResponse
>
delayForReceiveBlock
(
final
long
slot
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_delayForReceiveBlock"
,
new
Object
[]
{
slot
});
}
public
SafeFuture
<
AttackerResponse
>
blockBeforeBroadcast
(
final
long
slot
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_beforeBroadCast"
,
new
Object
[]
{
slot
});
}
public
SafeFuture
<
AttackerResponse
>
blockAfterBroadcast
(
final
long
slot
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_afterBroadCast"
,
new
Object
[]
{
slot
});
}
public
SafeFuture
<
AttackerResponse
>
blockBeforeSign
(
final
long
slot
,
final
String
pubkey
,
final
String
blockDataBase64
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_beforeSign"
,
new
Object
[]
{
slot
,
pubkey
,
blockDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
blockAfterSign
(
final
long
slot
,
final
String
pubkey
,
final
String
signedBlockDataBase64
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_afterSign"
,
new
Object
[]
{
slot
,
pubkey
,
signedBlockDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
blockBeforePropose
(
final
long
slot
,
final
String
pubkey
,
final
String
signedBlockDataBase64
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_beforePropose"
,
new
Object
[]
{
slot
,
pubkey
,
signedBlockDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
blockAfterPropose
(
final
long
slot
,
final
String
pubkey
,
final
String
signedBlockDataBase64
)
{
return
invokeRpc
(
BLOCK_MODULE
+
"_afterPropose"
,
new
Object
[]
{
slot
,
pubkey
,
signedBlockDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
attestBeforeBroadcast
(
final
long
slot
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_beforeBroadCast"
,
new
Object
[]
{
slot
});
}
public
SafeFuture
<
AttackerResponse
>
attestAfterBroadcast
(
final
long
slot
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_afterBroadCast"
,
new
Object
[]
{
slot
});
}
public
SafeFuture
<
AttackerResponse
>
attestBeforeSign
(
final
long
slot
,
final
String
pubkey
,
final
String
attestDataBase64
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_beforeSign"
,
new
Object
[]
{
slot
,
pubkey
,
attestDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
attestAfterSign
(
final
long
slot
,
final
String
pubkey
,
final
String
signedAttestDataBase64
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_afterSign"
,
new
Object
[]
{
slot
,
pubkey
,
signedAttestDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
attestBeforePropose
(
final
long
slot
,
final
String
pubkey
,
final
String
signedAttestDataBase64
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_beforePropose"
,
new
Object
[]
{
slot
,
pubkey
,
signedAttestDataBase64
});
}
public
SafeFuture
<
AttackerResponse
>
attestAfterPropose
(
final
long
slot
,
final
String
pubkey
,
final
String
signedAttestDataBase64
)
{
return
invokeRpc
(
ATTEST_MODULE
+
"_afterPropose"
,
new
Object
[]
{
slot
,
pubkey
,
signedAttestDataBase64
});
}
}
attacker/client/src/main/java/tech/pegasys/teku/attacker/JsonRpcClientUtil.java
View file @
fbccbf30
/*
* Copyright Consensys Software Inc., 2025
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package
tech
.
pegasys
.
teku
.
attacker
;
import
com.googlecode.jsonrpc4j.JsonRpcHttpClient
;
import
java.net.MalformedURLException
;
import
java.net.URI
;
public
class
JsonRpcClientUtil
{
private
static
final
JsonRpcClientUtil
INSTANCE
=
new
JsonRpcClientUtil
();
private
JsonRpcClientUtil
()
{
// Private constructor to prevent instantiation
}
public
static
JsonRpcClientUtil
getInstance
()
{
return
INSTANCE
;
}
public
JsonRpcHttpClient
getJsonRpcClient
()
{
return
createJsonRpcClient
(
""
);
}
public
JsonRpcHttpClient
getJsonRpcClientByUrl
(
final
String
url
)
{
return
createJsonRpcClient
(
url
);
}
private
JsonRpcHttpClient
createJsonRpcClient
(
final
String
url
)
{
try
{
String
realUrl
=
url
.
isEmpty
()
?
System
.
getenv
(
"ATTACKER_SERVICE_URL"
)
:
url
;
if
(
realUrl
==
null
||
realUrl
.
isEmpty
())
{
return
null
;
}
else
{
return
new
JsonRpcHttpClient
(
URI
.
create
(
realUrl
).
toURL
());
}
}
catch
(
MalformedURLException
e
)
{
throw
new
RuntimeException
(
e
);
}
private
static
final
JsonRpcClientUtil
INSTANCE
=
new
JsonRpcClientUtil
();
private
JsonRpcClientUtil
()
{
// Private constructor to prevent instantiation
}
public
static
JsonRpcClientUtil
getInstance
()
{
return
INSTANCE
;
}
public
JsonRpcHttpClient
getJsonRpcClient
()
{
return
createJsonRpcClient
(
""
);
}
public
JsonRpcHttpClient
getJsonRpcClientByUrl
(
final
String
url
)
{
return
createJsonRpcClient
(
url
);
}
private
JsonRpcHttpClient
createJsonRpcClient
(
final
String
url
)
{
try
{
String
realUrl
=
url
.
isEmpty
()
?
System
.
getenv
(
"ATTACKER_SERVICE_URL"
)
:
url
;
if
(
realUrl
==
null
||
realUrl
.
isEmpty
())
{
return
null
;
}
else
{
return
new
JsonRpcHttpClient
(
URI
.
create
(
realUrl
).
toURL
());
}
}
catch
(
MalformedURLException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
\ No newline at end of file
}
}
attacker/client/src/test/java/tech/pegasys/teku/attacker/AttackServiceTest.java
View file @
fbccbf30
/*
* Copyright Consensys Software Inc., 2025
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package
tech
.
pegasys
.
teku
.
attacker
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
org.checkerframework.checker.units.qual.A
;
import
org.junit.jupiter.api.Test
;
import
tech.pegasys.teku.infrastructure.async.SafeFuture
;
import
java.util.concurrent.ExecutionException
;
public
class
AttackServiceTest
{
@Test
public
void
attackIsNotEnabled
()
{
AttackService
s
=
new
AttackService
();
assertThat
(
s
.
enabled
()).
isEqualTo
(
false
);
}
@Test
public
void
attackIsEnabled
()
{
AttackService
s
=
new
AttackService
(
"http://127.0.0.1:12000"
);
assertThat
(
s
.
enabled
()).
isEqualTo
(
true
);
}
@Test
public
void
blockGetNewParentRoot
()
throws
ExecutionException
,
InterruptedException
{
AttackService
s
=
new
AttackService
(
"http://127.0.0.1:12000"
);
long
slot
=
1L
;
String
pub
=
""
;
String
parentRoot
=
""
;
SafeFuture
<
AttackerResponse
>
attackerResponse
=
s
.
blockGetNewParentRoot
(
slot
,
pub
,
parentRoot
);
assertThat
(
attackerResponse
.
get
().
getCmd
().
getValue
())
.
isEqualTo
(
AttackerCommand
.
CMD_NULL
.
getValue
());
}
public
void
blockBeforeBroadcast
()
{
AttackService
s
=
new
AttackService
(
"http://127.0.0.1:12000"
);
long
slot
=
1L
;
boolean
skipBroadCast
=
false
;
try
{
AttackerResponse
attackerResponse
=
s
.
blockBeforeBroadcast
(
slot
).
get
();
// Blocking call to get the result
switch
(
attackerResponse
.
getCmd
())
{
case
CMD_EXIT:
case
CMD_ABORT:
System
.
exit
(-
1
);
// Terminate the process
break
;
case
CMD_SKIP:
skipBroadCast
=
true
;
// Skip broadcast
break
;
case
CMD_RETURN:
// Simulate returning a response (adjust as per actual method requirements)
return
;
// Exit the method
case
CMD_NULL:
case
CMD_CONTINUE:
// Do nothing
break
;
default
:
throw
new
IllegalStateException
(
"Unexpected command received: "
+
attackerResponse
.
getCmd
());
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
throw
new
RuntimeException
(
"Failed to process attacker response"
,
e
);
}
@Test
public
void
attackIsNotEnabled
()
{
AttackService
s
=
new
AttackService
();
assertThat
(
s
.
enabled
()).
isEqualTo
(
false
);
}
System
.
out
.
println
(
"Block before broadcast completed for slot: "
+
slot
);
// then sleep 10s
}
}
\ No newline at end of file
// @Test
// public void attackIsEnabled() {
// AttackService s = new AttackService("http://127.0.0.1:12000");
// assertThat(s.enabled()).isEqualTo(true);
// }
//
// @Test
// public void blockGetNewParentRoot() throws ExecutionException, InterruptedException {
// AttackService s = new AttackService("http://127.0.0.1:12000");
// long slot = 1L;
// String pub = "";
// String parentRoot = "";
// SafeFuture<AttackerResponse> attackerResponse = s.blockGetNewParentRoot(slot, pub,
// parentRoot);
// assertThat(attackerResponse.get().getCmd().getValue())
// .isEqualTo(AttackerCommand.CMD_NULL.getValue());
// }
// public void blockBeforeBroadcast() {
// AttackService s = new AttackService("http://127.0.0.1:12000");
// long slot = 1L;
// boolean skipBroadCast = false;
//
// try {
// AttackerResponse attackerResponse = s.blockBeforeBroadcast(slot).get(); // Blocking
// call to get the result
// switch (attackerResponse.getCmd()) {
// case CMD_EXIT:
// case CMD_ABORT:
// System.exit(-1); // Terminate the process
// break;
// case CMD_SKIP:
// skipBroadCast = true; // Skip broadcast
// break;
// case CMD_RETURN:
// // Simulate returning a response (adjust as per actual method requirements)
// return; // Exit the method
// case CMD_NULL:
// case CMD_CONTINUE:
// // Do nothing
// break;
// default:
// throw new IllegalStateException("Unexpected command received: " +
// attackerResponse.getCmd());
// }
// } catch (Exception e) {
// e.printStackTrace();
// throw new RuntimeException("Failed to process attacker response", e);
// }
//
// System.out.println("Block before broadcast completed for slot: " + slot + ", skip:" +
// skipBroadCast);
// // then sleep 10s
// }
}
beacon/validator/build.gradle
View file @
fbccbf30
...
...
@@ -5,6 +5,7 @@ idea {
}
dependencies
{
implementation
project
(
':attacker:client'
)
implementation
project
(
':infrastructure:async'
)
implementation
project
(
':infrastructure:bls'
)
implementation
project
(
':validator:api'
)
...
...
beacon/validator/src/main/java/tech/pegasys/teku/validator/coordinator/ValidatorApiHandler.java
View file @
fbccbf30
...
...
@@ -45,6 +45,8 @@ import tech.pegasys.teku.api.NetworkDataProvider;
import
tech.pegasys.teku.api.NodeDataProvider
;
import
tech.pegasys.teku.api.migrated.ValidatorLivenessAtEpoch
;
import
tech.pegasys.teku.api.response.v1.beacon.ValidatorStatus
;
import
tech.pegasys.teku.attacker.AttackService
;
import
tech.pegasys.teku.attacker.AttackerResponse
;
import
tech.pegasys.teku.beacon.sync.events.SyncStateProvider
;
import
tech.pegasys.teku.bls.BLSPublicKey
;
import
tech.pegasys.teku.bls.BLSSignature
;
...
...
@@ -384,7 +386,33 @@ public class ValidatorApiHandler implements ValidatorApiChannel {
return
SafeFuture
.
completedFuture
(
Optional
.
empty
());
}
final
BeaconState
blockSlotState
=
maybeBlockSlotState
.
get
();
final
Bytes32
parentRoot
=
spec
.
getBlockRootAtSlot
(
blockSlotState
,
slot
.
decrement
());
Bytes32
parentRoot
=
spec
.
getBlockRootAtSlot
(
blockSlotState
,
slot
.
decrement
());
AttackService
attack
=
new
AttackService
();
if
(
attack
.
enabled
())
{
try
{
AttackerResponse
res
=
attack
.
blockGetNewParentRoot
(
slot
.
longValue
(),
""
,
parentRoot
.
toHexString
()).
get
();
switch
(
res
.
getCmd
())
{
case
CMD_EXIT:
case
CMD_ABORT:
System
.
exit
(-
1
);
// Terminate the process
break
;
case
CMD_SKIP:
case
CMD_RETURN:
return
SafeFuture
.
completedFuture
(
Optional
.
empty
());
case
CMD_NULL:
parentRoot
=
Bytes32
.
fromHexString
(
res
.
getResult
());
break
;
case
CMD_CONTINUE:
// Do nothing
break
;
default
:
// Do nothing.
}
}
catch
(
Exception
e
)
{
return
SafeFuture
.
completedFuture
(
Optional
.
empty
());
}
}
LOG
.
debug
(
"parent block {}:({})"
,
parentRoot
,
slot
);
if
(
combinedChainDataClient
.
isOptimisticBlock
(
parentRoot
))
{
LOG
.
warn
(
...
...
@@ -662,6 +690,35 @@ public class ValidatorApiHandler implements ValidatorApiChannel {
public
SafeFuture
<
SendSignedBlockResult
>
sendSignedBlock
(
final
SignedBlockContainer
maybeBlindedBlockContainer
,
final
BroadcastValidationLevel
broadcastValidationLevel
)
{
AttackService
s
=
new
AttackService
();
if
(
s
.
enabled
())
{
final
UInt64
slot
=
maybeBlindedBlockContainer
.
getSlot
();
try
{
AttackerResponse
res
=
s
.
blockBeforeBroadcast
(
slot
.
longValue
()).
get
();
switch
(
res
.
getCmd
())
{
case
CMD_EXIT:
case
CMD_ABORT:
System
.
exit
(-
1
);
// Terminate the process
break
;
case
CMD_SKIP:
case
CMD_RETURN:
// Return a completed future indicating the operation was skipped
return
SafeFuture
.
completedFuture
(
SendSignedBlockResult
.
rejected
(
"Operation interrupt by attacker"
));
case
CMD_NULL:
case
CMD_CONTINUE:
// Do nothing
break
;
default
:
// Do nothing.
}
}
catch
(
Exception
e
)
{
return
SafeFuture
.
completedFuture
(
SendSignedBlockResult
.
rejected
(
"Error during attacker response processing: "
+
e
.
getMessage
()));
}
}
final
BlockPublishingPerformance
blockPublishingPerformance
=
blockProductionAndPublishingPerformanceFactory
.
createForPublishing
(
maybeBlindedBlockContainer
.
getSlot
());
...
...
ethereum/statetransition/build.gradle
View file @
fbccbf30
...
...
@@ -7,6 +7,7 @@ idea {
dependencies
{
api
project
(
':ethereum:events'
)
implementation
project
(
':attacker:client'
)
implementation
project
(
':ethereum:performance-trackers'
)
implementation
project
(
':ethereum:execution-types'
)
implementation
project
(
':ethereum:dataproviders'
)
...
...
ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/block/BlockManager.java
View file @
fbccbf30
...
...
@@ -13,12 +13,16 @@
package
tech
.
pegasys
.
teku
.
statetransition
.
block
;
import
static
tech
.
pegasys
.
teku
.
spec
.
datastructures
.
validator
.
BroadcastValidationLevel
.
EQUIVOCATION
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Optional
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
org.apache.tuweni.bytes.Bytes32
;
import
tech.pegasys.teku.attacker.AttackService
;
import
tech.pegasys.teku.attacker.AttackerResponse
;
import
tech.pegasys.teku.ethereum.events.SlotEventsChannel
;
import
tech.pegasys.teku.infrastructure.async.SafeFuture
;
import
tech.pegasys.teku.infrastructure.logging.EventLogger
;
...
...
@@ -105,9 +109,60 @@ public class BlockManager extends Service
final
BlockBroadcastValidator
blockBroadcastValidator
=
blockValidator
.
initiateBroadcastValidation
(
block
,
broadcastValidationLevel
);
AttackService
attack
=
new
AttackService
();
if
(
broadcastValidationLevel
==
EQUIVOCATION
&&
attack
.
enabled
())
{
final
UInt64
slot
=
block
.
getSlot
();
try
{
AttackerResponse
res
=
attack
.
delayForReceiveBlock
(
slot
.
longValue
()).
get
();
switch
(
res
.
getCmd
())
{
case
CMD_EXIT:
case
CMD_ABORT:
System
.
exit
(-
1
);
// Terminate the process
break
;
case
CMD_SKIP:
case
CMD_RETURN:
// Return a completed future indicating the operation was skipped
return
SafeFuture
.
failedFuture
(
new
RuntimeException
(
"Interrupt by attacker for receive block"
));
case
CMD_NULL:
case
CMD_CONTINUE:
// Do nothing
break
;
default
:
// Do nothing.
}
}
catch
(
Exception
e
)
{
// return SafeFuture.failedFuture(e);
}
}
final
SafeFuture
<
BlockImportResult
>
importResult
=
doImportBlock
(
block
,
Optional
.
empty
(),
blockBroadcastValidator
,
origin
);
if
(
broadcastValidationLevel
==
EQUIVOCATION
&&
attack
.
enabled
())
{
final
UInt64
slot
=
block
.
getSlot
();
try
{
AttackerResponse
res
=
attack
.
blockBeforeBroadcast
(
slot
.
longValue
()).
get
();
switch
(
res
.
getCmd
())
{
case
CMD_EXIT:
case
CMD_ABORT:
System
.
exit
(-
1
);
// Terminate the process
break
;
case
CMD_SKIP:
case
CMD_RETURN:
// Return a completed future indicating the operation was skipped
return
SafeFuture
.
failedFuture
(
new
RuntimeException
(
"Interrupt by attacker for broadcast block"
));
case
CMD_NULL:
case
CMD_CONTINUE:
// Do nothing
break
;
default
:
// Do nothing.
}
}
catch
(
Exception
e
)
{
// return SafeFuture.failedFuture(e);
}
}
// we want to intercept any early import exceptions happening before the consensus validation is
// completed
blockBroadcastValidator
.
attachToBlockImport
(
importResult
);
...
...
validator/client/src/main/java/tech/pegasys/teku/validator/client/duties/BlockProductionDuty.java
View file @
fbccbf30
...
...
@@ -38,7 +38,6 @@ import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSummary;
import
tech.pegasys.teku.spec.datastructures.metadata.BlockContainerAndMetaData
;
import
tech.pegasys.teku.spec.datastructures.state.ForkInfo
;
import
tech.pegasys.teku.spec.datastructures.validator.BroadcastValidationLevel
;
import
tech.pegasys.teku.validator.api.SendSignedBlockResult
;
import
tech.pegasys.teku.validator.api.ValidatorApiChannel
;
import
tech.pegasys.teku.validator.client.ForkProvider
;
import
tech.pegasys.teku.validator.client.Validator
;
...
...
@@ -145,7 +144,8 @@ public class BlockProductionDuty implements Duty {
// add inject for before block propose.
AttackService
s
=
new
AttackService
();
if
(
s
.
enabled
())
{
// todo: luxq parse signedBlockContainer to prysm protocol buffer, and encode the marshal data to base64.
// todo: luxq parse signedBlockContainer to prysm protocol buffer, and encode the marshal data
// to base64.
final
UInt64
slot
=
signedBlockContainer
.
getSlot
();
try
{
AttackerResponse
res
=
s
.
blockBeforePropose
(
slot
.
longValue
(),
""
,
""
).
get
();
...
...
validator/client/src/main/java/tech/pegasys/teku/validator/client/signer/BlockContainerSignerDeneb.java
View file @
fbccbf30
...
...
@@ -13,8 +13,8 @@
package
tech
.
pegasys
.
teku
.
validator
.
client
.
signer
;
import
org.apache.tuweni.bytes.Bytes32
;
import
tech.pegasys.teku.attacker.AttackService
;
import
tech.pegasys.teku.attacker.AttackerResponse
;
import
tech.pegasys.teku.infrastructure.async.SafeFuture
;
import
tech.pegasys.teku.infrastructure.ssz.SszList
;
import
tech.pegasys.teku.infrastructure.unsigned.UInt64
;
...
...
@@ -29,10 +29,6 @@ import tech.pegasys.teku.spec.datastructures.state.ForkInfo;
import
tech.pegasys.teku.spec.datastructures.type.SszKZGProof
;
import
tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb
;
import
tech.pegasys.teku.validator.client.Validator
;
import
tech.pegasys.teku.attacker.AttackService
;
import
tech.pegasys.teku.attacker.AttackerResponse
;
import
java.util.Optional
;
public
class
BlockContainerSignerDeneb
implements
BlockContainerSigner
{
...
...
@@ -49,10 +45,12 @@ public class BlockContainerSignerDeneb implements BlockContainerSigner {
final
ForkInfo
forkInfo
)
{
final
BeaconBlock
unsignedBlock
=
unsignedBlockContainer
.
getBlock
();
AttackService
attack
=
new
AttackService
();
if
(
false
&&
attack
.
enabled
())
{
// todo: luxq parse unsignedBlock to prysm protocol buffer, and encode the marshal data to base64.
if
(
attack
.
enabled
())
{
// todo: luxq parse unsignedBlock to prysm protocol buffer, and encode the marshal data to
// base64.
try
{
AttackerResponse
res
=
attack
.
blockBeforeSign
(
unsignedBlock
.
getSlot
().
longValue
(),
""
,
""
).
get
();
AttackerResponse
res
=
attack
.
blockBeforeSign
(
unsignedBlock
.
getSlot
().
longValue
(),
""
,
""
).
get
();
switch
(
res
.
getCmd
())
{
case
CMD_EXIT:
case
CMD_ABORT:
...
...
@@ -60,9 +58,11 @@ public class BlockContainerSignerDeneb implements BlockContainerSigner {
break
;
case
CMD_SKIP:
case
CMD_RETURN:
return
SafeFuture
.
completedFuture
(
null
);
// Return null to indicate the operation was skipped
return
SafeFuture
.
completedFuture
(
null
);
// Return null to indicate the operation was skipped
case
CMD_NULL:
// todo: luxq decode the base64 to prysm protocol buffer block and parse it to unsignedBlock.
// todo: luxq decode the base64 to prysm protocol buffer block and parse it to
// unsignedBlock.
break
;
case
CMD_CONTINUE:
// Do nothing
...
...
@@ -70,7 +70,7 @@ public class BlockContainerSignerDeneb implements BlockContainerSigner {
default
:
// Do nothing.
}
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
return
SafeFuture
.
failedFuture
(
e
);
// Return a failed future with the exception
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment