Add more debug timing logs.

Adding tests.
Update AllTests.
This commit is contained in:
cheatfate 2023-05-17 12:49:22 +03:00
parent 0f9d3e4f39
commit 59732f9393
No known key found for this signature in database
GPG Key ID: 46ADD633A7201F95
3 changed files with 408 additions and 8 deletions

View File

@ -40,6 +40,10 @@ type
validatorSyncCommitteeIndex: IndexInSyncCommittee
validatorSubCommitteeIndex: SyncSubcommitteeIndex
FillSignaturesResult = object
signaturesRequested: int
signaturesReceived: int
chronicles.formatIt(DutiesServiceLoop):
case it
of AttesterLoop: "attester_loop"
@ -142,7 +146,7 @@ proc pollForValidatorIndices*(service: DutiesServiceRef) {.async.} =
proc fillAttestationSlotSignatures*(
service: DutiesServiceRef,
epochPeriods: seq[Epoch]
) {.async.} =
): Future[FillSignaturesResult] {.async.} =
let
vc = service.client
genesisRoot = vc.beaconGenesis.genesis_validators_root
@ -171,10 +175,13 @@ proc fillAttestationSlotSignatures*(
# of validators. In this case tasks that run concurrently will be able to use
# signatures for slots at the beginning of the epoch even before this
# processing will be completed.
var sigres = FillSignaturesResult()
for chunk in requests.chunks(ATTESTATION_SIGNING_CHUNK_SIZE):
let pendingRequests = chunk.mapIt(
getSlotSignature(it.validator, it.fork, genesisRoot, it.slot))
inc(sigres.signaturesRequested, len(chunk))
try:
await allFutures(pendingRequests)
except CancelledError as exc:
@ -196,6 +203,7 @@ proc fillAttestationSlotSignatures*(
slot = request.slot
Opt.none(ValidatorSig)
else:
inc(sigres.signaturesReceived)
Opt.some(sres.get())
else:
Opt.none(ValidatorSig)
@ -282,6 +290,8 @@ proc fillAttestationSlotSignatures*(
map[].duties.withValue(selection.slot.epoch(), dap):
dap[].slotSig = Opt.some(selectionProof.toValidatorSig())
return sigres
proc pollForAttesterDuties*(service: DutiesServiceRef,
epoch: Epoch): Future[int] {.async.} =
let vc = service.client
@ -392,7 +402,7 @@ proc pruneSyncCommitteeDuties*(service: DutiesServiceRef, slot: Slot) =
proc fillSyncSlotSignatures*(
service: DutiesServiceRef,
epochPeriods: seq[Epoch]
) {.async.} =
): Future[FillSignaturesResult] {.async.} =
let
vc = service.client
genesisRoot = vc.beaconGenesis.genesis_validators_root
@ -428,6 +438,7 @@ proc fillSyncSlotSignatures*(
validatorSubCommitteeIndex: subCommitteeIndex))
res
var sigres = FillSignaturesResult()
# We creating signatures in chunks to make VC more responsive for big number
# of validators. In this case tasks that run concurrently will be able to use
# signatures for slots at the beginning of the epoch even before this
@ -438,6 +449,8 @@ proc fillSyncSlotSignatures*(
it.validator, it.fork, genesisRoot, it.slot,
it.validatorSubCommitteeIndex))
inc(sigres.signaturesRequested, len(chunk))
try:
await allFutures(pendingRequests)
except CancelledError as exc:
@ -462,6 +475,7 @@ proc fillSyncSlotSignatures*(
validator = shortLog(request.validator)
Opt.none(ValidatorSig)
else:
inc(sigres.signaturesReceived)
Opt.some(sres.get())
else:
Opt.none(ValidatorSig)
@ -563,6 +577,8 @@ proc fillSyncSlotSignatures*(
sdap[].slotSigs.withValue(subCommitteeIndex, proofs):
proofs[][slotIndex] = Opt.some(selectionProof.toValidatorSig())
return sigres
proc pollForSyncCommitteeDuties*(service: DutiesServiceRef,
epoch: Epoch): Future[int] {.async.} =
let vc = service.client
@ -672,9 +688,14 @@ proc pollForAttesterDuties*(service: DutiesServiceRef) {.async.} =
debug "No new attester's duties received", slot = currentSlot
block:
let moment = Moment.now()
await service.fillAttestationSlotSignatures(@[currentEpoch, nextEpoch])
debug "Slot signatures has been obtained", time = (Moment.now() - moment)
let
moment = Moment.now()
sigres = await service.fillAttestationSlotSignatures(
@[currentEpoch, nextEpoch])
debug "Slot signatures has been received",
signatures_requested = sigres.signaturesRequested,
signatures_received = sigres.signaturesReceived,
time = (Moment.now() - moment)
let subscriptions =
block:
@ -754,9 +775,12 @@ proc pollForSyncCommitteeDuties*(service: DutiesServiceRef) {.async.} =
slot = currentSlot
block:
let moment = Moment.now()
await service.fillSyncSlotSignatures(epochs)
let
moment = Moment.now()
sigres = await service.fillSyncSlotSignatures(epochs)
debug "Sync selection proofs has been obtained",
signatures_requested = sigres.signaturesRequested,
signatures_received = sigres.signaturesReceived,
time = (Moment.now() - moment)
let subscriptions =

View File

@ -47,6 +47,7 @@ import # Unit test
./test_validator_pool,
./test_zero_signature,
./test_signing_node,
./test_validator_client,
./consensus_spec/all_tests as consensus_all_tests,
./slashing_protection/test_fixtures,
./slashing_protection/test_slashing_protection_db,

View File

@ -143,9 +143,384 @@ const
("", "err(Missing hostname)")
]
ObolBeaconRequestTestVector = """
[
{
"validator_index": "1",
"slot": "1",
"selection_proof": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
},
{
"slot": "2",
"validator_index": "2",
"selection_proof": "0x2b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
},
{
"validator_index": "3",
"selection_proof": "0x3b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505",
"slot": "3"
},
{
"selection_proof": "0x4b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505",
"validator_index": "4",
"slot": "4"
}
]"""
ObolBeaconResponseTestVector = """
{
"data": [
{
"validator_index": "1",
"slot": "1",
"selection_proof": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
},
{
"validator_index": "2",
"slot": "2",
"selection_proof": "0x2b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
},
{
"validator_index": "3",
"slot": "3",
"selection_proof": "0x3b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
},
{
"validator_index": "4",
"slot": "4",
"selection_proof": "0x4b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
}
]
}"""
ObolBeaconResponseTestVectorObject = [
(
validator_index: RestValidatorIndex(1),
slot: Slot(1),
selection_proof: "1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
),
(
validator_index: RestValidatorIndex(2),
slot: Slot(2),
selection_proof: "2b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
),
(
validator_index: RestValidatorIndex(3),
slot: Slot(3),
selection_proof: "3b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
),
(
validator_index: RestValidatorIndex(4),
slot: Slot(4),
selection_proof: "4b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
)
]
ObolSyncRequestTestVector = """
[
{
"validator_index": "1",
"slot": "1",
"subcommittee_index": "1",
"selection_proof": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
},
{
"validator_index": "2",
"subcommittee_index": "2",
"slot": "2",
"selection_proof": "0x2b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
},
{
"subcommittee_index": "3",
"validator_index": "3",
"slot": "3",
"selection_proof": "0x3b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
},
{
"validator_index": "4",
"slot": "4",
"selection_proof": "0x4b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505",
"subcommittee_index": "4"
}
]"""
ObolSyncResponseTestVector = """
{
"data": [
{
"validator_index": "1",
"slot": "1",
"subcommittee_index": "1",
"selection_proof": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
},
{
"validator_index": "2",
"subcommittee_index": "2",
"slot": "2",
"selection_proof": "0x2b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
},
{
"subcommittee_index": "3",
"validator_index": "3",
"slot": "3",
"selection_proof": "0x3b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
},
{
"validator_index": "4",
"slot": "4",
"selection_proof": "0x4b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505",
"subcommittee_index": "4"
}
]
}"""
ObolSyncResponseTestVectorObject = [
(
validator_index: RestValidatorIndex(1),
slot: Slot(1),
subcommittee_index: 1'u64,
selection_proof: "1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
),
(
validator_index: RestValidatorIndex(2),
slot: Slot(2),
subcommittee_index: 2'u64,
selection_proof: "2b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
),
(
validator_index: RestValidatorIndex(3),
slot: Slot(3),
subcommittee_index: 3'u64,
selection_proof: "3b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
),
(
validator_index: RestValidatorIndex(4),
slot: Slot(4),
subcommittee_index: 4'u64,
selection_proof: "4b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
)
]
type
TestDecodeTypes = seq[RestBeaconCommitteeSelection] |
seq[RestSyncCommitteeSelection]
suite "Validator Client test suite":
proc decodeBytes[T: TestDecodeTypes](
t: typedesc[T],
value: openArray[byte],
contentType: Opt[ContentTypeData] = Opt.none(ContentTypeData)
): RestResult[T] =
let mediaType =
if contentType.isNone():
ApplicationJsonMediaType
else:
if isWildCard(contentType.get().mediaType):
return err("Incorrect Content-Type")
contentType.get().mediaType
if mediaType == ApplicationJsonMediaType:
try:
ok RestJson.decode(value, T,
requireAllFields = true,
allowUnknownFields = true)
except SerializationError as exc:
err("Serialization error")
else:
err("Content-Type not supported")
proc submitBeaconCommitteeSelectionsPlain*(
body: seq[RestBeaconCommitteeSelection]
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/beacon_committee_selections",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Validator/submitBeaconCommitteeSelections
proc submitSyncCommitteeSelectionsPlain*(
body: seq[RestSyncCommitteeSelection]
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/sync_committee_selections",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Validator/submitSyncCommitteeSelections
proc createServer(address: TransportAddress,
process: HttpProcessCallback, secure: bool): HttpServerRef =
let
socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
res = HttpServerRef.new(address, process, socketFlags = socketFlags)
res.get()
test "normalizeUri() test vectors":
for hostname in HostNames:
for vector in GoodTestVectors:
let expect = vector[1] % (hostname)
check $normalizeUri(parseUri(vector[0] % (hostname))) == expect
asyncTest "/eth/v1/validator/sync_committee_selections " &
"serialization/deserialization test":
var clientRequest: seq[byte]
proc process(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isOk():
let request = r.get()
case request.uri.path
of "/eth/v1/validator/beacon_committee_selections":
clientRequest = await request.getBody()
let headers = HttpTable.init([("Content-Type", "application/json")])
return await request.respond(Http200, ObolBeaconResponseTestVector,
headers)
else:
return await request.respond(Http404, "Page not found")
else:
return dumbResponse()
let server = createServer(initTAddress("127.0.0.1:0"), process, false)
server.start()
defer:
await server.stop()
await server.closeWait()
let
serverAddress = server.instance.localAddress
flags = {RestClientFlag.CommaSeparatedArray}
remoteUri = "http://" & $serverAddress
client =
block:
let res = RestClientRef.new(remoteUri, flags = flags)
check res.isOk()
res.get()
selections =
block:
let res = decodeBytes(
seq[RestBeaconCommitteeSelection],
ObolBeaconRequestTestVector.toOpenArrayByte(
0, len(ObolBeaconRequestTestVector) - 1))
check res.isOk()
res.get()
defer:
await client.closeWait()
let resp = await client.submitBeaconCommitteeSelectionsPlain(selections)
check:
resp.status == 200
resp.contentType == MediaType.init("application/json")
let request =
block:
let res = decodeBytes(
seq[RestBeaconCommitteeSelection],
clientRequest)
check res.isOk()
res.get()
let response = block:
let res = decodeBytes(SubmitBeaconCommitteeSelectionsResponse,
resp.data, resp.contentType)
check res.isOk()
res.get()
check:
len(request) == len(selections)
len(response.data) == len(ObolBeaconResponseTestVectorObject)
# Checking response
for index, item in response.data.pairs():
check:
item.validator_index ==
ObolBeaconResponseTestVectorObject[index].validator_index
item.slot ==
ObolBeaconResponseTestVectorObject[index].slot
item.selection_proof.toHex() ==
ObolBeaconResponseTestVectorObject[index].selection_proof
# Checking request
for index, item in selections.pairs():
check:
item.validator_index == request[index].validator_index
item.slot == request[index].slot
item.selection_proof.toHex() == request[index].selection_proof.toHex()
asyncTest "/eth/v1/validator/sync_committee_selections " &
"serialization/deserialization test":
var clientRequest: seq[byte]
proc process(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isOk():
let request = r.get()
case request.uri.path
of "/eth/v1/validator/sync_committee_selections":
clientRequest = await request.getBody()
let headers = HttpTable.init([("Content-Type", "application/json")])
return await request.respond(Http200, ObolSyncResponseTestVector,
headers)
else:
return await request.respond(Http404, "Page not found")
else:
return dumbResponse()
let server = createServer(initTAddress("127.0.0.1:0"), process, false)
server.start()
defer:
await server.stop()
await server.closeWait()
let
serverAddress = server.instance.localAddress
flags = {RestClientFlag.CommaSeparatedArray}
remoteUri = "http://" & $serverAddress
client =
block:
let res = RestClientRef.new(remoteUri, flags = flags)
check res.isOk()
res.get()
selections =
block:
let res = decodeBytes(
seq[RestSyncCommitteeSelection],
ObolSyncRequestTestVector.toOpenArrayByte(
0, len(ObolSyncRequestTestVector) - 1))
check res.isOk()
res.get()
defer:
await client.closeWait()
let resp = await client.submitSyncCommitteeSelectionsPlain(selections)
check:
resp.status == 200
resp.contentType == MediaType.init("application/json")
let request =
block:
let res = decodeBytes(
seq[RestSyncCommitteeSelection],
clientRequest)
check res.isOk()
res.get()
let response = block:
let res = decodeBytes(SubmitSyncCommitteeSelectionsResponse,
resp.data, resp.contentType)
check res.isOk()
res.get()
check:
len(request) == len(selections)
len(response.data) == len(ObolSyncResponseTestVectorObject)
# Checking response
for index, item in response.data.pairs():
check:
item.validator_index ==
ObolSyncResponseTestVectorObject[index].validator_index
item.slot ==
ObolSyncResponseTestVectorObject[index].slot
item.selection_proof.toHex() ==
ObolSyncResponseTestVectorObject[index].selection_proof
item.subcommittee_index == request[index].subcommittee_index
# Checking request
for index, item in selections.pairs():
check:
item.validator_index == request[index].validator_index
item.slot == request[index].slot
item.subcommittee_index == request[index].subcommittee_index
item.selection_proof.toHex() == request[index].selection_proof.toHex()