Add attester/proposer slashing endpoints (#856)
* Remove deprecated api_spec.yaml * add prototype for proposer slashing * remove clippy warnings * Add proposer_slashing API * Prototype for attester slashing API call * Fix logic error in operation pool * Finish test for attester_slashing api call * Clean proposer_slashing test * Cargo fmt * Remove useless to_string after format! macro * Cargo fmt * Update book with new api calls * Re-enable proposer slashing verification * Update book with appropriate test example * Fix proposer_slashing test * Update comments and tests for clearer code * Remove extraneous comments * Fix test * Minor fix * Address reviewer comments Co-authored-by: pscott <30843220+pscott@users.noreply.github.com>
This commit is contained in:
parent
7a880dd23c
commit
74c34d1602
@ -10,8 +10,8 @@ use ssz_derive::{Decode, Encode};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use store::Store;
|
use store::Store;
|
||||||
use types::{
|
use types::{
|
||||||
BeaconState, CommitteeIndex, EthSpec, Hash256, PublicKeyBytes, RelativeEpoch,
|
AttesterSlashing, BeaconState, CommitteeIndex, EthSpec, Hash256, ProposerSlashing,
|
||||||
SignedBeaconBlock, Slot, Validator,
|
PublicKeyBytes, RelativeEpoch, SignedBeaconBlock, Slot, Validator,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Information about the block and state that are at head of the beacon chain.
|
/// Information about the block and state that are at head of the beacon chain.
|
||||||
@ -496,3 +496,75 @@ pub fn get_genesis_time<T: BeaconChainTypes>(
|
|||||||
) -> ApiResult {
|
) -> ApiResult {
|
||||||
ResponseBuilder::new(&req)?.body(&beacon_chain.head()?.beacon_state.genesis_time)
|
ResponseBuilder::new(&req)?.body(&beacon_chain.head()?.beacon_state.genesis_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn proposer_slashing<T: BeaconChainTypes>(
|
||||||
|
req: Request<Body>,
|
||||||
|
beacon_chain: Arc<BeaconChain<T>>,
|
||||||
|
) -> BoxFut {
|
||||||
|
let response_builder = ResponseBuilder::new(&req);
|
||||||
|
|
||||||
|
let future = req
|
||||||
|
.into_body()
|
||||||
|
.concat2()
|
||||||
|
.map_err(|e| ApiError::ServerError(format!("Unable to get request body: {:?}", e)))
|
||||||
|
.and_then(|chunks| {
|
||||||
|
serde_json::from_slice::<ProposerSlashing>(&chunks).map_err(|e| {
|
||||||
|
ApiError::BadRequest(format!(
|
||||||
|
"Unable to parse JSON into ProposerSlashing: {:?}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.and_then(move |proposer_slashing| {
|
||||||
|
let spec = &beacon_chain.spec;
|
||||||
|
let state = &beacon_chain.head().unwrap().beacon_state;
|
||||||
|
beacon_chain
|
||||||
|
.op_pool
|
||||||
|
.insert_proposer_slashing(proposer_slashing, state, spec)
|
||||||
|
.map_err(|e| {
|
||||||
|
ApiError::BadRequest(format!(
|
||||||
|
"Error while inserting proposer slashing: {:?}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.and_then(|_| response_builder?.body(&true));
|
||||||
|
|
||||||
|
Box::new(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attester_slashing<T: BeaconChainTypes>(
|
||||||
|
req: Request<Body>,
|
||||||
|
beacon_chain: Arc<BeaconChain<T>>,
|
||||||
|
) -> BoxFut {
|
||||||
|
let response_builder = ResponseBuilder::new(&req);
|
||||||
|
|
||||||
|
let future = req
|
||||||
|
.into_body()
|
||||||
|
.concat2()
|
||||||
|
.map_err(|e| ApiError::ServerError(format!("Unable to get request body: {:?}", e)))
|
||||||
|
.and_then(|chunks| {
|
||||||
|
serde_json::from_slice::<AttesterSlashing<T::EthSpec>>(&chunks).map_err(|e| {
|
||||||
|
ApiError::BadRequest(format!(
|
||||||
|
"Unable to parse JSON into AttesterSlashing: {:?}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.and_then(move |attester_slashing| {
|
||||||
|
let spec = &beacon_chain.spec;
|
||||||
|
let state = &beacon_chain.head().unwrap().beacon_state;
|
||||||
|
beacon_chain
|
||||||
|
.op_pool
|
||||||
|
.insert_attester_slashing(attester_slashing, state, spec)
|
||||||
|
.map_err(|e| {
|
||||||
|
ApiError::BadRequest(format!(
|
||||||
|
"Error while inserting attester slashing: {:?}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.and_then(|_| response_builder?.body(&true));
|
||||||
|
|
||||||
|
Box::new(future)
|
||||||
|
}
|
||||||
|
@ -104,6 +104,12 @@ pub fn route<T: BeaconChainTypes>(
|
|||||||
(&Method::GET, "/beacon/committees") => {
|
(&Method::GET, "/beacon/committees") => {
|
||||||
into_boxfut(beacon::get_committees::<T>(req, beacon_chain))
|
into_boxfut(beacon::get_committees::<T>(req, beacon_chain))
|
||||||
}
|
}
|
||||||
|
(&Method::POST, "/beacon/proposer_slashing") => {
|
||||||
|
into_boxfut(beacon::proposer_slashing::<T>(req, beacon_chain))
|
||||||
|
}
|
||||||
|
(&Method::POST, "/beacon/attester_slashing") => {
|
||||||
|
into_boxfut(beacon::attester_slashing::<T>(req, beacon_chain))
|
||||||
|
}
|
||||||
|
|
||||||
// Methods for Validator
|
// Methods for Validator
|
||||||
(&Method::POST, "/validator/duties") => {
|
(&Method::POST, "/validator/duties") => {
|
||||||
|
@ -12,9 +12,12 @@ use remote_beacon_node::{
|
|||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::{
|
use types::{
|
||||||
test_utils::generate_deterministic_keypair, BeaconBlock, BeaconState, ChainSpec, Domain, Epoch,
|
test_utils::{
|
||||||
EthSpec, MinimalEthSpec, PublicKey, RelativeEpoch, Signature, SignedBeaconBlock, SignedRoot,
|
build_double_vote_attester_slashing, build_proposer_slashing,
|
||||||
Slot, Validator,
|
generate_deterministic_keypair, AttesterSlashingTestTask, ProposerSlashingTestTask,
|
||||||
|
},
|
||||||
|
BeaconBlock, BeaconState, ChainSpec, Domain, Epoch, EthSpec, MinimalEthSpec, PublicKey,
|
||||||
|
RelativeEpoch, Signature, SignedBeaconBlock, SignedRoot, Slot, Validator,
|
||||||
};
|
};
|
||||||
use version;
|
use version;
|
||||||
|
|
||||||
@ -862,3 +865,158 @@ fn compare_validator_response<T: EthSpec>(
|
|||||||
assert_eq!(state.balances[i], balance, "balances");
|
assert_eq!(state.balances[i], balance, "balances");
|
||||||
assert_eq!(state.validators[i], *validator, "validator index");
|
assert_eq!(state.validators[i], *validator, "validator index");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn proposer_slashing() {
|
||||||
|
let mut env = build_env();
|
||||||
|
|
||||||
|
let node = build_node(&mut env, testing_client_config());
|
||||||
|
let remote_node = node.remote_node().expect("should produce remote node");
|
||||||
|
let chain = node
|
||||||
|
.client
|
||||||
|
.beacon_chain()
|
||||||
|
.expect("node should have beacon chain");
|
||||||
|
|
||||||
|
let state = chain
|
||||||
|
.head()
|
||||||
|
.expect("should have retrieved state")
|
||||||
|
.beacon_state;
|
||||||
|
|
||||||
|
let spec = &chain.spec;
|
||||||
|
|
||||||
|
// Check that there are no proposer slashings before insertion
|
||||||
|
let (proposer_slashings, _attester_slashings) = chain.op_pool.get_slashings(&state, spec);
|
||||||
|
assert_eq!(proposer_slashings.len(), 0);
|
||||||
|
|
||||||
|
let slot = state.slot;
|
||||||
|
let proposer_index = chain
|
||||||
|
.block_proposer(slot)
|
||||||
|
.expect("should get proposer index");
|
||||||
|
let keypair = generate_deterministic_keypair(proposer_index);
|
||||||
|
let key = &keypair.sk;
|
||||||
|
let fork = &state.fork;
|
||||||
|
let proposer_slashing = build_proposer_slashing::<E>(
|
||||||
|
ProposerSlashingTestTask::Valid,
|
||||||
|
proposer_index as u64,
|
||||||
|
&key,
|
||||||
|
fork,
|
||||||
|
spec,
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = env
|
||||||
|
.runtime()
|
||||||
|
.block_on(
|
||||||
|
remote_node
|
||||||
|
.http
|
||||||
|
.beacon()
|
||||||
|
.proposer_slashing(proposer_slashing.clone()),
|
||||||
|
)
|
||||||
|
.expect("should fetch from http api");
|
||||||
|
assert!(result, true);
|
||||||
|
|
||||||
|
// Length should be just one as we've inserted only one proposer slashing
|
||||||
|
let (proposer_slashings, _attester_slashings) = chain.op_pool.get_slashings(&state, spec);
|
||||||
|
assert_eq!(proposer_slashings.len(), 1);
|
||||||
|
assert_eq!(proposer_slashing.clone(), proposer_slashings[0]);
|
||||||
|
|
||||||
|
let mut invalid_proposer_slashing = build_proposer_slashing::<E>(
|
||||||
|
ProposerSlashingTestTask::Valid,
|
||||||
|
proposer_index as u64,
|
||||||
|
&key,
|
||||||
|
fork,
|
||||||
|
spec,
|
||||||
|
);
|
||||||
|
invalid_proposer_slashing.signed_header_2 = invalid_proposer_slashing.signed_header_1.clone();
|
||||||
|
|
||||||
|
let result = env.runtime().block_on(
|
||||||
|
remote_node
|
||||||
|
.http
|
||||||
|
.beacon()
|
||||||
|
.proposer_slashing(invalid_proposer_slashing),
|
||||||
|
);
|
||||||
|
assert!(result.is_err());
|
||||||
|
|
||||||
|
// Length should still be one as we've inserted nothing since last time.
|
||||||
|
let (proposer_slashings, _attester_slashings) = chain.op_pool.get_slashings(&state, spec);
|
||||||
|
assert_eq!(proposer_slashings.len(), 1);
|
||||||
|
assert_eq!(proposer_slashing, proposer_slashings[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn attester_slashing() {
|
||||||
|
let mut env = build_env();
|
||||||
|
|
||||||
|
let node = build_node(&mut env, testing_client_config());
|
||||||
|
let remote_node = node.remote_node().expect("should produce remote node");
|
||||||
|
let chain = node
|
||||||
|
.client
|
||||||
|
.beacon_chain()
|
||||||
|
.expect("node should have beacon chain");
|
||||||
|
|
||||||
|
let state = chain
|
||||||
|
.head()
|
||||||
|
.expect("should have retrieved state")
|
||||||
|
.beacon_state;
|
||||||
|
let slot = state.slot;
|
||||||
|
let spec = &chain.spec;
|
||||||
|
|
||||||
|
let proposer_index = chain
|
||||||
|
.block_proposer(slot)
|
||||||
|
.expect("should get proposer index");
|
||||||
|
let keypair = generate_deterministic_keypair(proposer_index);
|
||||||
|
|
||||||
|
let secret_keys = vec![&keypair.sk];
|
||||||
|
let validator_indices = vec![proposer_index as u64];
|
||||||
|
let fork = &state.fork;
|
||||||
|
|
||||||
|
// Checking there are no attester slashings before insertion
|
||||||
|
let (_proposer_slashings, attester_slashings) = chain.op_pool.get_slashings(&state, spec);
|
||||||
|
assert_eq!(attester_slashings.len(), 0);
|
||||||
|
|
||||||
|
let attester_slashing = build_double_vote_attester_slashing(
|
||||||
|
AttesterSlashingTestTask::Valid,
|
||||||
|
&validator_indices[..],
|
||||||
|
&secret_keys[..],
|
||||||
|
fork,
|
||||||
|
spec,
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = env
|
||||||
|
.runtime()
|
||||||
|
.block_on(
|
||||||
|
remote_node
|
||||||
|
.http
|
||||||
|
.beacon()
|
||||||
|
.attester_slashing(attester_slashing.clone()),
|
||||||
|
)
|
||||||
|
.expect("should fetch from http api");
|
||||||
|
assert!(result, true);
|
||||||
|
|
||||||
|
// Length should be just one as we've inserted only one attester slashing
|
||||||
|
let (_proposer_slashings, attester_slashings) = chain.op_pool.get_slashings(&state, spec);
|
||||||
|
assert_eq!(attester_slashings.len(), 1);
|
||||||
|
assert_eq!(attester_slashing, attester_slashings[0]);
|
||||||
|
|
||||||
|
// Building an invalid attester slashing
|
||||||
|
let mut invalid_attester_slashing = build_double_vote_attester_slashing(
|
||||||
|
AttesterSlashingTestTask::Valid,
|
||||||
|
&validator_indices[..],
|
||||||
|
&secret_keys[..],
|
||||||
|
fork,
|
||||||
|
spec,
|
||||||
|
);
|
||||||
|
invalid_attester_slashing.attestation_2 = invalid_attester_slashing.attestation_1.clone();
|
||||||
|
|
||||||
|
let result = env.runtime().block_on(
|
||||||
|
remote_node
|
||||||
|
.http
|
||||||
|
.beacon()
|
||||||
|
.attester_slashing(invalid_attester_slashing),
|
||||||
|
);
|
||||||
|
assert!(result.is_err());
|
||||||
|
|
||||||
|
// Length should still be one as we've failed to insert the attester slashing.
|
||||||
|
let (_proposer_slashings, attester_slashings) = chain.op_pool.get_slashings(&state, spec);
|
||||||
|
assert_eq!(attester_slashings.len(), 1);
|
||||||
|
assert_eq!(attester_slashing, attester_slashings[0]);
|
||||||
|
}
|
||||||
|
@ -7,19 +7,283 @@ beacon chain and also historical information about beacon blocks and states.
|
|||||||
|
|
||||||
HTTP Path | Description |
|
HTTP Path | Description |
|
||||||
| --- | -- |
|
| --- | -- |
|
||||||
|
[`/beacon/attester_slashing`](#beaconattester_slashing) | Insert an attester slashing
|
||||||
|
[`/beacon/block`](#beaconblock) | Get a `BeaconBlock` by slot or root.
|
||||||
|
[`/beacon/block_root`](#beaconblock_root) | Resolve a slot to a block root.
|
||||||
|
[`/beacon/committees`](#beaconcommittees) | Get the shuffling for an epoch.
|
||||||
[`/beacon/head`](#beaconhead) | Info about the block at the head of the chain.
|
[`/beacon/head`](#beaconhead) | Info about the block at the head of the chain.
|
||||||
[`/beacon/heads`](#beaconheads) | Returns a list of all known chain heads.
|
[`/beacon/heads`](#beaconheads) | Returns a list of all known chain heads.
|
||||||
[`/beacon/block_root`](#beaconblock_root) | Resolve a slot to a block root.
|
[`/beacon/proposer_slashing`](#beaconproposer_slashing) | Insert a proposer slashing
|
||||||
[`/beacon/block`](#beaconblock) | Get a `SignedBeaconBlock` by slot or root.
|
|
||||||
[`/beacon/state_root`](#beaconstate_root) | Resolve a slot to a state root.
|
|
||||||
[`/beacon/state`](#beaconstate) | Get a `BeaconState` by slot or root.
|
[`/beacon/state`](#beaconstate) | Get a `BeaconState` by slot or root.
|
||||||
|
[`/beacon/state_root`](#beaconstate_root) | Resolve a slot to a state root.
|
||||||
[`/beacon/state/genesis`](#beaconstategenesis) | Get a `BeaconState` at genesis.
|
[`/beacon/state/genesis`](#beaconstategenesis) | Get a `BeaconState` at genesis.
|
||||||
[`/beacon/genesis_time`](#beacongenesis_time) | Get the genesis time from the beacon state.
|
[`/beacon/genesis_time`](#beacongenesis_time) | Get the genesis time from the beacon state.
|
||||||
[`/beacon/fork`](#beaconfork) | Get the fork of the head of the chain.
|
[`/beacon/fork`](#beaconfork) | Get the fork of the head of the chain.
|
||||||
[`/beacon/validators`](#beaconvalidators) | Query for one or more validators.
|
[`/beacon/validators`](#beaconvalidators) | Query for one or more validators.
|
||||||
[`/beacon/validators/all`](#beaconvalidatorsall) | Get all validators.
|
|
||||||
[`/beacon/validators/active`](#beaconvalidatorsactive) | Get all active validators.
|
[`/beacon/validators/active`](#beaconvalidatorsactive) | Get all active validators.
|
||||||
[`/beacon/committees`](#beaconcommittees) | Get the shuffling for an epoch.
|
[`/beacon/validators/all`](#beaconvalidatorsall) | Get all validators.
|
||||||
|
|
||||||
|
## `/beacon/attester_slashing`
|
||||||
|
|
||||||
|
Accepts an `attester_slashing` and verifies it. If it is valid, it is added to the operations pool for potential inclusion in a future block. Returns a 400 error if the `attester_slashing` is invalid.
|
||||||
|
|
||||||
|
### HTTP Specification
|
||||||
|
|
||||||
|
| Property | Specification |
|
||||||
|
| --- |--- |
|
||||||
|
Path | `/beacon/attester_slashing`
|
||||||
|
Method | POST
|
||||||
|
JSON Encoding | Object
|
||||||
|
Query Parameters | None
|
||||||
|
Typical Responses | 200/400
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
Expects the following object in the POST request body:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
attestation_1: {
|
||||||
|
attesting_indices: [u64],
|
||||||
|
data: {
|
||||||
|
slot: Slot,
|
||||||
|
index: u64,
|
||||||
|
beacon_block_root: Bytes32,
|
||||||
|
source: {
|
||||||
|
epoch: Epoch,
|
||||||
|
root: Bytes32
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
epoch: Epoch,
|
||||||
|
root: Bytes32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signature: Bytes32
|
||||||
|
},
|
||||||
|
attestation_2: {
|
||||||
|
attesting_indices: [u64],
|
||||||
|
data: {
|
||||||
|
slot: Slot,
|
||||||
|
index: u64,
|
||||||
|
beacon_block_root: Bytes32,
|
||||||
|
source: {
|
||||||
|
epoch: Epoch,
|
||||||
|
root: Bytes32
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
epoch: Epoch,
|
||||||
|
root: Bytes32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signature: Bytes32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Returns
|
||||||
|
|
||||||
|
Returns `true` if the attester slashing was inserted successfully, or the corresponding error if it failed.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
### Request Body
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"attestation_1": {
|
||||||
|
"attesting_indices": [0],
|
||||||
|
"data": {
|
||||||
|
"slot": 1,
|
||||||
|
"index": 0,
|
||||||
|
"beacon_block_root": "0x0000000000000000000000000000000000000000000000000100000000000000",
|
||||||
|
"source": {
|
||||||
|
"epoch": 1,
|
||||||
|
"root": "0x0000000000000000000000000000000000000000000000000100000000000000"
|
||||||
|
},
|
||||||
|
"target": {
|
||||||
|
"epoch": 1,
|
||||||
|
"root": "0x0000000000000000000000000000000000000000000000000100000000000000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"signature": "0xb47f7397cd944b8d5856a13352166bbe74c85625a45b14b7347fc2c9f6f6f82acee674c65bc9ceb576fcf78387a6731c0b0eb3f8371c70db2da4e7f5dfbc451730c159d67263d3db56b6d0e009e4287a8ba3efcacac30b3ae3447e89dc71b5b9"
|
||||||
|
},
|
||||||
|
"attestation_2": {
|
||||||
|
"attesting_indices": [0],
|
||||||
|
"data": {
|
||||||
|
"slot": 1,
|
||||||
|
"index": 0,
|
||||||
|
"beacon_block_root": "0x0000000000000000000000000000000000000000000000000100000000000000",
|
||||||
|
"source": {
|
||||||
|
"epoch": 1,
|
||||||
|
"root": "0x0000000000000000000000000000000000000000000000000100000000000000"
|
||||||
|
},
|
||||||
|
"target": {
|
||||||
|
"epoch": 1,
|
||||||
|
"root": "0x0000000000000000000000000000000000000000000000000200000000000000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"signature": "0x93fef587a63acf72aaf8df627718fd43cb268035764071f802ffb4370a2969d226595cc650f4c0bf2291ae0c0a41fcac1700f318603d75d34bcb4b9f4a8368f61eeea0e1f5d969d92d5073ba5fbadec102b45ec87d418d25168d2e3c74b9fcbb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
_Note: data sent here is for demonstration purposes only_
|
||||||
|
|
||||||
|
## `/beacon/block`
|
||||||
|
|
||||||
|
Request that the node return a beacon chain block that matches the provided
|
||||||
|
criteria (a block `root` or beacon chain `slot`). Only one of the parameters
|
||||||
|
should be provided as a criteria.
|
||||||
|
|
||||||
|
### HTTP Specification
|
||||||
|
|
||||||
|
| Property | Specification |
|
||||||
|
| --- |--- |
|
||||||
|
Path | `/beacon/block`
|
||||||
|
Method | GET
|
||||||
|
JSON Encoding | Object
|
||||||
|
Query Parameters | `slot`, `root`
|
||||||
|
Typical Responses | 200, 404
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
Accepts **only one** of the following parameters:
|
||||||
|
|
||||||
|
- `slot` (`Slot`): Query by slot number. Any block returned must be in the canonical chain (i.e.,
|
||||||
|
either the head or an ancestor of the head).
|
||||||
|
- `root` (`Bytes32`): Query by tree hash root. A returned block is not required to be in the
|
||||||
|
canonical chain.
|
||||||
|
|
||||||
|
### Returns
|
||||||
|
|
||||||
|
Returns an object containing a single [`SignedBeaconBlock`](https://github.com/ethereum/eth2.0-specs/blob/v0.10.0/specs/phase0/beacon-chain.md#signedbeaconblock) and the block root of the inner [`BeaconBlock`](https://github.com/ethereum/eth2.0-specs/blob/v0.10.0/specs/phase0/beacon-chain.md#beaconblock).
|
||||||
|
|
||||||
|
### Example Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"root": "0xc35ddf4e71c31774e0594bd7eb32dfe50b54dbc40abd594944254b4ec8895196",
|
||||||
|
"beacon_block": {
|
||||||
|
"message": {
|
||||||
|
"slot": 0,
|
||||||
|
"parent_root": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"state_root": "0xf15690b6be4ed42ea1ee0741eb4bfd4619d37be8229b84b4ddd480fb028dcc8f",
|
||||||
|
"body": {
|
||||||
|
"randao_reveal": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"eth1_data": {
|
||||||
|
"deposit_root": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"deposit_count": 0,
|
||||||
|
"block_hash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
},
|
||||||
|
"graffiti": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"proposer_slashings": [],
|
||||||
|
"attester_slashings": [],
|
||||||
|
"attestations": [],
|
||||||
|
"deposits": [],
|
||||||
|
"voluntary_exits": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"signature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `/beacon/block_root`
|
||||||
|
|
||||||
|
Returns the block root for the given slot in the canonical chain. If there
|
||||||
|
is a re-org, the same slot may return a different root.
|
||||||
|
|
||||||
|
### HTTP Specification
|
||||||
|
|
||||||
|
| Property | Specification |
|
||||||
|
| --- |--- |
|
||||||
|
Path | `/beacon/block_root`
|
||||||
|
Method | GET
|
||||||
|
JSON Encoding | Object
|
||||||
|
Query Parameters | `slot`
|
||||||
|
Typical Responses | 200, 404
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
- `slot` (`Slot`): the slot to be resolved to a root.
|
||||||
|
|
||||||
|
### Example Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
"0xc35ddf4e71c31774e0594bd7eb32dfe50b54dbc40abd594944254b4ec8895196"
|
||||||
|
```
|
||||||
|
|
||||||
|
## `/beacon/committees`
|
||||||
|
|
||||||
|
Request the committees (a.k.a. "shuffling") for all slots and committee indices
|
||||||
|
in a given `epoch`.
|
||||||
|
|
||||||
|
### HTTP Specification
|
||||||
|
|
||||||
|
| Property | Specification |
|
||||||
|
| --- |--- |
|
||||||
|
Path | `/beacon/committees`
|
||||||
|
Method | GET
|
||||||
|
JSON Encoding | Object
|
||||||
|
Query Parameters | `epoch`
|
||||||
|
Typical Responses | 200/500
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
The `epoch` (`Epoch`) query parameter is required and defines the epoch for
|
||||||
|
which the committees will be returned. All slots contained within the response will
|
||||||
|
be inside this epoch.
|
||||||
|
|
||||||
|
### Returns
|
||||||
|
|
||||||
|
A list of beacon committees.
|
||||||
|
|
||||||
|
### Example Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"slot": 4768,
|
||||||
|
"index": 0,
|
||||||
|
"committee": [
|
||||||
|
1154,
|
||||||
|
492,
|
||||||
|
9667,
|
||||||
|
3089,
|
||||||
|
8987,
|
||||||
|
1421,
|
||||||
|
224,
|
||||||
|
11243,
|
||||||
|
2127,
|
||||||
|
2329,
|
||||||
|
188,
|
||||||
|
482,
|
||||||
|
486
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slot": 4768,
|
||||||
|
"index": 1,
|
||||||
|
"committee": [
|
||||||
|
5929,
|
||||||
|
8482,
|
||||||
|
5528,
|
||||||
|
6130,
|
||||||
|
14343,
|
||||||
|
9777,
|
||||||
|
10808,
|
||||||
|
12739,
|
||||||
|
15234,
|
||||||
|
12819,
|
||||||
|
5423,
|
||||||
|
6320,
|
||||||
|
9991
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
_Truncated for brevity._
|
||||||
|
|
||||||
## `/beacon/head`
|
## `/beacon/head`
|
||||||
|
|
||||||
@ -82,115 +346,76 @@ Typical Responses | 200
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
## `/beacon/block_root`
|
## `/beacon/proposer_slashing`
|
||||||
|
|
||||||
Returns the block root for the given slot in the canonical chain. If there
|
Accepts a `proposer_slashing` and verifies it. If it is valid, it is added to the operations pool for potential inclusion in a future block. Returns an 400 error if the `proposer_slashing` is invalid.
|
||||||
is a re-org, the same slot may return a different root.
|
|
||||||
|
|
||||||
### HTTP Specification
|
### HTTP Specification
|
||||||
|
|
||||||
| Property | Specification |
|
| Property | Specification |
|
||||||
| --- |--- |
|
| --- |--- |
|
||||||
Path | `/beacon/block_root`
|
Path | `/beacon/proposer_slashing`
|
||||||
Method | GET
|
Method | POST
|
||||||
JSON Encoding | Object
|
JSON Encoding | Object
|
||||||
Query Parameters | `slot`
|
Query Parameters | None
|
||||||
Typical Responses | 200, 404
|
Typical Responses | 200/400
|
||||||
|
|
||||||
## Parameters
|
### Request Body
|
||||||
|
|
||||||
- `slot` (`Slot`): the slot to be resolved to a root.
|
Expects the following object in the POST request body:
|
||||||
|
|
||||||
### Example Response
|
|
||||||
|
|
||||||
```json
|
|
||||||
"0xc35ddf4e71c31774e0594bd7eb32dfe50b54dbc40abd594944254b4ec8895196"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## `/beacon/block`
|
|
||||||
|
|
||||||
Request that the node return a beacon chain block that matches the provided
|
|
||||||
criteria (a block `root` or beacon chain `slot`). Only one of the parameters
|
|
||||||
should be provided as a criteria.
|
|
||||||
|
|
||||||
### HTTP Specification
|
|
||||||
|
|
||||||
| Property | Specification |
|
|
||||||
| --- |--- |
|
|
||||||
Path | `/beacon/block`
|
|
||||||
Method | GET
|
|
||||||
JSON Encoding | Object
|
|
||||||
Query Parameters | `slot`, `root`
|
|
||||||
Typical Responses | 200, 404
|
|
||||||
|
|
||||||
### Parameters
|
|
||||||
|
|
||||||
Accepts **only one** of the following parameters:
|
|
||||||
|
|
||||||
- `slot` (`Slot`): Query by slot number. Any block returned must be in the canonical chain (i.e.,
|
|
||||||
either the head or an ancestor of the head).
|
|
||||||
- `root` (`Bytes32`): Query by tree hash root. A returned block is not required to be in the
|
|
||||||
canonical chain.
|
|
||||||
|
|
||||||
### Returns
|
|
||||||
|
|
||||||
Returns an object containing a single [`SignedBeaconBlock`](https://github.com/ethereum/eth2.0-specs/blob/v0.10.0/specs/phase0/beacon-chain.md#signedbeaconblock) and the block root of the inner [`BeaconBlock`](https://github.com/ethereum/eth2.0-specs/blob/v0.10.0/specs/phase0/beacon-chain.md#beaconblock).
|
|
||||||
|
|
||||||
### Example Response
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
{
|
||||||
"root": "0xc35ddf4e71c31774e0594bd7eb32dfe50b54dbc40abd594944254b4ec8895196",
|
proposer_index: u64,
|
||||||
"beacon_block": {
|
header_1: {
|
||||||
"message": {
|
slot: Slot,
|
||||||
"slot": 0,
|
parent_root: Bytes32,
|
||||||
"parent_root": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
state_root: Bytes32,
|
||||||
"state_root": "0xf15690b6be4ed42ea1ee0741eb4bfd4619d37be8229b84b4ddd480fb028dcc8f",
|
body_root: Bytes32,
|
||||||
"body": {
|
signature: Bytes32
|
||||||
"randao_reveal": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
},
|
||||||
"eth1_data": {
|
header_2: {
|
||||||
"deposit_root": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
slot: Slot,
|
||||||
"deposit_count": 0,
|
parent_root: Bytes32,
|
||||||
"block_hash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
state_root: Bytes32,
|
||||||
},
|
body_root: Bytes32,
|
||||||
"graffiti": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
signature: Bytes32
|
||||||
"proposer_slashings": [],
|
|
||||||
"attester_slashings": [],
|
|
||||||
"attestations": [],
|
|
||||||
"deposits": [],
|
|
||||||
"voluntary_exits": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"signature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## `/beacon/state_root`
|
### Returns
|
||||||
|
|
||||||
Returns the state root for the given slot in the canonical chain. If there
|
Returns `true` if the proposer slashing was inserted successfully, or the corresponding error if it failed.
|
||||||
is a re-org, the same slot may return a different root.
|
|
||||||
|
|
||||||
### HTTP Specification
|
### Example
|
||||||
|
|
||||||
| Property | Specification |
|
### Request Body
|
||||||
| --- |--- |
|
|
||||||
Path | `/beacon/state_root`
|
|
||||||
Method | GET
|
|
||||||
JSON Encoding | Object
|
|
||||||
Query Parameters | `slot`
|
|
||||||
Typical Responses | 200, 404
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
- `slot` (`Slot`): the slot to be resolved to a root.
|
|
||||||
|
|
||||||
### Example Response
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"0xf15690b6be4ed42ea1ee0741eb4bfd4619d37be8229b84b4ddd480fb028dcc8f"
|
{
|
||||||
|
"proposer_index": 0,
|
||||||
|
"header_1": {
|
||||||
|
"slot": 0,
|
||||||
|
"parent_root": "0x0101010101010101010101010101010101010101010101010101010101010101",
|
||||||
|
"state_root": "0x0101010101010101010101010101010101010101010101010101010101010101",
|
||||||
|
"body_root": "0x0101010101010101010101010101010101010101010101010101010101010101",
|
||||||
|
"signature": "0xb8970d1342c6d5779c700ec366efd0ca819937ca330960db3ca5a55eb370a3edd83f4cbb2f74d06e82f934fcbd4bb80609a19c2254cc8b3532a4efff9e80edf312ac735757c059d77126851e377f875593e64ba50d1dffe69a809a409202dd12"
|
||||||
|
},
|
||||||
|
"header_2": {
|
||||||
|
"slot": 0,
|
||||||
|
"parent_root": "0x0202020202020202020202020202020202020202020202020202020202020202",
|
||||||
|
"state_root": "0x0101010101010101010101010101010101010101010101010101010101010101",
|
||||||
|
"body_root": "0x0101010101010101010101010101010101010101010101010101010101010101",
|
||||||
|
"signature": "0xb60e6b348698a34e59b22e0af96f8809f977f00f95d52375383ade8d22e9102270a66c6d52b0434214897e11ca4896871510c01b3fd74d62108a855658d5705fcfc4ced5136264a1c6496f05918576926aa191b1ad311b7e27f5aa2167aba294"
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
_Note: data sent here is for demonstration purposes only_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## `/beacon/state`
|
## `/beacon/state`
|
||||||
|
|
||||||
Request that the node return a beacon chain state that matches the provided
|
Request that the node return a beacon chain state that matches the provided
|
||||||
@ -236,6 +461,32 @@ and its tree hash root.
|
|||||||
|
|
||||||
_Truncated for brevity._
|
_Truncated for brevity._
|
||||||
|
|
||||||
|
## `/beacon/state_root`
|
||||||
|
|
||||||
|
Returns the state root for the given slot in the canonical chain. If there
|
||||||
|
is a re-org, the same slot may return a different root.
|
||||||
|
|
||||||
|
|
||||||
|
### HTTP Specification
|
||||||
|
|
||||||
|
| Property | Specification |
|
||||||
|
| --- |--- |
|
||||||
|
Path | `/beacon/state_root`
|
||||||
|
Method | GET
|
||||||
|
JSON Encoding | Object
|
||||||
|
Query Parameters | `slot`
|
||||||
|
Typical Responses | 200, 404
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
- `slot` (`Slot`): the slot to be resolved to a root.
|
||||||
|
|
||||||
|
### Example Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
"0xf15690b6be4ed42ea1ee0741eb4bfd4619d37be8229b84b4ddd480fb028dcc8f"
|
||||||
|
```
|
||||||
|
|
||||||
## `/beacon/state/genesis`
|
## `/beacon/state/genesis`
|
||||||
|
|
||||||
Request that the node return a beacon chain state at genesis (slot 0).
|
Request that the node return a beacon chain state at genesis (slot 0).
|
||||||
@ -405,30 +656,6 @@ _Note: for demonstration purposes the second pubkey is some unknown pubkey._
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
## `/beacon/validators/all`
|
|
||||||
|
|
||||||
Returns all validators.
|
|
||||||
|
|
||||||
### HTTP Specification
|
|
||||||
|
|
||||||
| Property | Specification |
|
|
||||||
| --- |--- |
|
|
||||||
Path | `/beacon/validators/all`
|
|
||||||
Method | GET
|
|
||||||
JSON Encoding | Object
|
|
||||||
Query Parameters | `state_root` (optional)
|
|
||||||
Typical Responses | 200
|
|
||||||
|
|
||||||
### Parameters
|
|
||||||
|
|
||||||
The optional `state_root` (`Bytes32`) query parameter indicates which
|
|
||||||
`BeaconState` should be used to collect the information. When omitted, the
|
|
||||||
canonical head state will be used.
|
|
||||||
|
|
||||||
### Returns
|
|
||||||
|
|
||||||
The return format is identical to the [`/beacon/validators`](#beaconvalidators) response body.
|
|
||||||
|
|
||||||
## `/beacon/validators/active`
|
## `/beacon/validators/active`
|
||||||
|
|
||||||
Returns all validators that are active in the state defined by `state_root`.
|
Returns all validators that are active in the state defined by `state_root`.
|
||||||
@ -453,74 +680,26 @@ canonical head state will be used.
|
|||||||
|
|
||||||
The return format is identical to the [`/beacon/validators`](#beaconvalidators) response body.
|
The return format is identical to the [`/beacon/validators`](#beaconvalidators) response body.
|
||||||
|
|
||||||
## `/beacon/committees`
|
## `/beacon/validators/all`
|
||||||
|
|
||||||
Request the committees (a.k.a. "shuffling") for all slots and committee indices
|
Returns all validators.
|
||||||
in a given `epoch`.
|
|
||||||
|
|
||||||
### HTTP Specification
|
### HTTP Specification
|
||||||
|
|
||||||
| Property | Specification |
|
| Property | Specification |
|
||||||
| --- |--- |
|
| --- |--- |
|
||||||
Path | `/beacon/committees`
|
Path | `/beacon/validators/all`
|
||||||
Method | GET
|
Method | GET
|
||||||
JSON Encoding | Object
|
JSON Encoding | Object
|
||||||
Query Parameters | `epoch`
|
Query Parameters | `state_root` (optional)
|
||||||
Typical Responses | 200
|
Typical Responses | 200
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
The `epoch` (`Epoch`) query parameter is required and defines the epoch for
|
The optional `state_root` (`Bytes32`) query parameter indicates which
|
||||||
which the committees will be returned. All slots contained within the response will
|
`BeaconState` should be used to collect the information. When omitted, the
|
||||||
be inside this epoch.
|
canonical head state will be used.
|
||||||
|
|
||||||
### Returns
|
### Returns
|
||||||
|
|
||||||
A list of beacon committees.
|
The return format is identical to the [`/beacon/validators`](#beaconvalidators) response body.
|
||||||
|
|
||||||
### Example Response
|
|
||||||
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"slot": 4768,
|
|
||||||
"index": 0,
|
|
||||||
"committee": [
|
|
||||||
1154,
|
|
||||||
492,
|
|
||||||
9667,
|
|
||||||
3089,
|
|
||||||
8987,
|
|
||||||
1421,
|
|
||||||
224,
|
|
||||||
11243,
|
|
||||||
2127,
|
|
||||||
2329,
|
|
||||||
188,
|
|
||||||
482,
|
|
||||||
486
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"slot": 4768,
|
|
||||||
"index": 1,
|
|
||||||
"committee": [
|
|
||||||
5929,
|
|
||||||
8482,
|
|
||||||
5528,
|
|
||||||
6130,
|
|
||||||
14343,
|
|
||||||
9777,
|
|
||||||
10808,
|
|
||||||
12739,
|
|
||||||
15234,
|
|
||||||
12819,
|
|
||||||
5423,
|
|
||||||
6320,
|
|
||||||
9991
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
_Truncated for brevity._
|
|
@ -377,7 +377,7 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
|
|||||||
/// Builds an `ProposerSlashing` for some `validator_index`.
|
/// Builds an `ProposerSlashing` for some `validator_index`.
|
||||||
///
|
///
|
||||||
/// Signs the message using a `BeaconChainHarness`.
|
/// Signs the message using a `BeaconChainHarness`.
|
||||||
fn build_proposer_slashing<T: EthSpec>(
|
pub fn build_proposer_slashing<T: EthSpec>(
|
||||||
test_task: ProposerSlashingTestTask,
|
test_task: ProposerSlashingTestTask,
|
||||||
validator_index: u64,
|
validator_index: u64,
|
||||||
secret_key: &SecretKey,
|
secret_key: &SecretKey,
|
||||||
@ -396,7 +396,7 @@ fn build_proposer_slashing<T: EthSpec>(
|
|||||||
/// Builds an `AttesterSlashing` for some `validator_indices`.
|
/// Builds an `AttesterSlashing` for some `validator_indices`.
|
||||||
///
|
///
|
||||||
/// Signs the message using a `BeaconChainHarness`.
|
/// Signs the message using a `BeaconChainHarness`.
|
||||||
fn build_double_vote_attester_slashing<T: EthSpec>(
|
pub fn build_double_vote_attester_slashing<T: EthSpec>(
|
||||||
test_task: AttesterSlashingTestTask,
|
test_task: AttesterSlashingTestTask,
|
||||||
validator_indices: &[u64],
|
validator_indices: &[u64],
|
||||||
secret_keys: &[&SecretKey],
|
secret_keys: &[&SecretKey],
|
||||||
|
@ -14,8 +14,8 @@ use ssz::Encode;
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use types::{
|
use types::{
|
||||||
Attestation, BeaconBlock, BeaconState, CommitteeIndex, Epoch, EthSpec, Fork, Hash256,
|
Attestation, AttesterSlashing, BeaconBlock, BeaconState, CommitteeIndex, Epoch, EthSpec, Fork,
|
||||||
PublicKey, Signature, SignedBeaconBlock, Slot,
|
Hash256, ProposerSlashing, PublicKey, Signature, SignedBeaconBlock, Slot,
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@ -500,6 +500,38 @@ impl<E: EthSpec> Beacon<E> {
|
|||||||
client.json_get(url, vec![("epoch".into(), format!("{}", epoch.as_u64()))])
|
client.json_get(url, vec![("epoch".into(), format!("{}", epoch.as_u64()))])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn proposer_slashing(
|
||||||
|
&self,
|
||||||
|
proposer_slashing: ProposerSlashing,
|
||||||
|
) -> impl Future<Item = bool, Error = Error> {
|
||||||
|
let client = self.0.clone();
|
||||||
|
|
||||||
|
self.url("proposer_slashing")
|
||||||
|
.into_future()
|
||||||
|
.and_then(move |url| {
|
||||||
|
client
|
||||||
|
.json_post::<_>(url, proposer_slashing)
|
||||||
|
.and_then(|response| error_for_status(response).map_err(Error::from))
|
||||||
|
.and_then(|mut success| success.json().map_err(Error::from))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attester_slashing(
|
||||||
|
&self,
|
||||||
|
attester_slashing: AttesterSlashing<E>,
|
||||||
|
) -> impl Future<Item = bool, Error = Error> {
|
||||||
|
let client = self.0.clone();
|
||||||
|
|
||||||
|
self.url("attester_slashing")
|
||||||
|
.into_future()
|
||||||
|
.and_then(move |url| {
|
||||||
|
client
|
||||||
|
.json_post::<_>(url, attester_slashing)
|
||||||
|
.and_then(|response| error_for_status(response).map_err(Error::from))
|
||||||
|
.and_then(|mut success| success.json().map_err(Error::from))
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides the functions on the `/spec` endpoint of the node.
|
/// Provides the functions on the `/spec` endpoint of the node.
|
||||||
|
Loading…
Reference in New Issue
Block a user