NodeUpdateTransaction - Test specification
Description:
This test specification for NodeUpdateTransaction is to be one of many for testing the functionality of the Hedera SDKs. The SDK under test will use the language specific JSON-RPC server return responses back to the test driver.
Design:
Each test within the test specification is linked to one of the functions within NodeUpdateTransaction. Each function is tested with a mix of boundaries. The inputs for each test are a range of valid, minimum, maximum, negative and invalid values for the method. The expected response of a passed test can be a correct error response code or seen as the result of node queries. A successful transaction (the transaction reached consensus and was applied to state) can be determined by getting a TransactionReceipt or TransactionRecord, or can be determined by using queries such as AddressBookQuery and investigating for the required changes (creations, updates, etc.). The mirror node can also be used to determine if a transaction was successful via its rest API. Error codes are obtained from the response code proto files.
Transaction properties:
https://docs.hedera.com/hedera/sdks-and-apis/sdks/node-service
Node protobufs:
https://github.com/hashgraph/hedera-protobufs/blob/main/services/node_update.proto
Response codes:
https://github.com/hashgraph/hedera-protobufs/blob/main/services/response_code.proto
Mirror Node APIs:
https://docs.hedera.com/hedera/sdks-and-apis/rest-api
JSON-RPC API Endpoint Documentation
Method Name
updateNode
Input Parameters
| Parameter Name | Type | Required/Optional | Description/Notes |
|---|---|---|---|
| nodeId | string | optional | The ID of the node to update. |
| accountId | string | optional | The account ID that will be associated with the node. |
| description | string | optional | A short description of the node (max 100 bytes). |
| gossipEndpoints | array of ServiceEndpointParams | optional | List of service endpoints for gossip (max 10 entries). |
| serviceEndpoints | array of ServiceEndpointParams | optional | List of service endpoints for gRPC calls (max 8 entries). |
| gossipCaCertificate | string | optional | Certificate used to sign gossip events (DER encoding). |
| grpcCertificateHash | string | optional | Hash of the node gRPC TLS certificate (SHA-384). |
| grpcWebProxyEndpoint | ServiceEndpointParams | optional | Proxy endpoint for gRPC web calls. |
| adminKey | string | optional | Administrative key controlled by the node operator. |
| declineReward | boolean | optional | Whether the node declines rewards. |
| commonTransactionParams | json object | optional | Common transaction parameters. |
Output Parameters
| Parameter Name | Type | Description/Notes |
|---|---|---|
| status | string | The status of the submitted transaction (from a TransactionReceipt). |
Additional Notes
The tests contained in this specification will assume that valid accounts were already successfully created. <CREATED_ACCOUNT_ID> will denote the ID of the account associated with the node, and <CREATED_ACCOUNT_PRIVATE_KEY> will denote the private key of the account as a DER-encoded hex string. Tests will assume valid admin keys have already been generated. <CREATED_ADMIN_KEY> will denote the admin key as a DER-encoded hex string. <VALID_GOSSIP_CERTIFICATE> will denote a valid DER-encoded certificate for gossip signing.
Property/Function Tests
NodeId:
- Tests the node identifier parameter for updating a consensus node
| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---|---|---|---|---|
| 1 | Updates a node with a valid node ID | nodeId=<EXISTING_NODE_ID> | The node update is successful | Y |
| 2 | Cannot update a node with an invalid node ID | nodeId=<NON_EXISTING_NODE_ID> | The node update fails with INVALID_NODE_ID | Y |
| 3 | Cannot update a node without providing a node ID | The node update fails with internal SDK error | Y | |
| 4 | Cannot update a node with a negative node ID | nodeId="-1" | The node update fails with internal SDK error | Y |
| 5 | Cannot update a node with uint64 max node ID | nodeId="18,446,744,073,709,551,615" | The node update fails with INVALID_NODE_ID | Y |
AccountId:
- Tests the account ID parameter for updating a consensus node
| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---|---|---|---|---|
| 1 | Updates a node with valid account ID | nodeId=<EXISTING_NODE_ID>, accountId=<CREATED_ACCOUNT_ID>, adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds. | Y |
| 2 | Fails with empty account ID | nodeId=<EXISTING_NODE_ID>, accountId="", adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with an SDK internal error. | Y |
| 3 | Fails with non-existent account ID | nodeId=<EXISTING_NODE_ID>, accountId="123.456.789", adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with an INVALID_ACCOUNT_ID response code. | Y |
| 4 | Fails with invalid account ID | nodeId=<EXISTING_NODE_ID>, accountId="invalid.account.id", adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with an SDK internal error. | Y |
Description:
- Tests the description parameter with various lengths and formats
| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---|---|---|---|---|
| 1 | Updates a node with valid description | nodeId=<EXISTING_NODE_ID>, description="test description" adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds and the node has the specified description. | Y |
| 2 | Updates a node with description at maximum length (100 bytes) | nodeId=<EXISTING_NODE_ID>, description=<100_BYTE_STRING> adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds and the node has the specified description. | Y |
| 3 | Updates a node with description exceeding maximum length | nodeId=<EXISTING_NODE_ID>, description=<101_BYTE_STRING> adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | INTERNAL_ERROR | Y |
| 4 | Updates a node with description containing only whitespace | nodeId=<EXISTING_NODE_ID>, description=" " adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds and the node has the whitespace description. | Y |
| 5 | Updates a node with description containing special characters | nodeId=<EXISTING_NODE_ID>, description="!@#$%^&*()_+-=[]{};':",./<>?" adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds and the node has the special character description. | Y |
| 6 | Updates a node with description containing unicode characters | nodeId=<EXISTING_NODE_ID>, description="测试节点描述 🚀" adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds and the node has the unicode description. | Y |
| 7 | Updates a node with description containing exactly 100 ASCII characters | nodeId=<EXISTING_NODE_ID>, description="a".repeat(100) adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds and the node has the 100-character description. | Y |
| 8 | Updates a node with description containing exactly 100 UTF-8 bytes (fewer characters) | nodeId=<EXISTING_NODE_ID>, description="🚀".repeat(25) adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds and the node has the 100-byte description. | Y |
GossipEndpoints:
- Tests the gossip endpoints parameter with various configurations
| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---|---|---|---|---|
| 1 | Update a node with single IP address endpoint | nodeId=<EXISTING_NODE_ID>, gossipEndpoints=[{ipAddressV4=<VALID_HEX_IP_ADDRESS>, port=50211}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds. | Y |
| 2 | Update a node with domain name endpoint | nodeId=<EXISTING_NODE_ID>, gossipEndpoints=[{domainName="node.example.com", port=50211}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds. | Y |
| 3 | Update a node with multiple gossip endpoints | nodeId=<EXISTING_NODE_ID>, gossipEndpoints=[{ipAddressV4=<VALID_HEX_IP_ADDRESS>, port=50211}, {ipAddressV4=<VALID_HEX_IP_ADDRESS_2>, port=50212}, {domainName="node.example.com", port=50213}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds. | Y |
| 4 | Update a node with maximum allowed gossip endpoints (10) | nodeId=<EXISTING_NODE_ID>, gossipEndpoints=[10 endpoints], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds. | Y |
| 5 | Fails with too many gossip endpoints (11) | nodeId=<EXISTING_NODE_ID>, gossipEndpoints=[11 endpoints], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | INTERNAL_ERROR | Y |
| 6 | Fails with empty gossip endpoints | nodeId=<EXISTING_NODE_ID>, gossipEndpoints=[], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | Internal error | Y |
| 7 | Fails with missing port in endpoint | nodeId=<EXISTING_NODE_ID>, gossipEndpoints=[{ipAddressV4=<VALID_HEX_IP_ADDRESS>}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with INVALID_ENDPOINT. | Y |
| 8 | Fails with both IP and domain in same endpoint | nodeId=<EXISTING_NODE_ID>, gossipEndpoints=[{ipAddressV4=<VALID_HEX_IP_ADDRESS>, domainName="node.example.com", port=50211}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with an SDK internal error. | Y |
| 9 | Fails with invalid IP address format | nodeId=<EXISTING_NODE_ID>, gossipEndpoints=[{ipAddressV4=<INVALID_HEX_IP_ADDRESS>, port=50211}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with INVALID_ENDPOINT. | Y |
| 10 | Fails with invalid port number (negative) | nodeId=<EXISTING_NODE_ID>, gossipEndpoints=[{ipAddressV4=<VALID_HEX_IP_ADDRESS>, port=-1}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with an SDK internal error. | Y |
| 11 | Fails with invalid port number (too high) | nodeId=<EXISTING_NODE_ID>, gossipEndpoints=[{ipAddressV4=<VALID_HEX_IP_ADDRESS>, port=65536}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with an SDK internal error. | Y |
ServiceEndpoints:
- Tests the service endpoints parameter with various configurations
| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---|---|---|---|---|
| 1 | Updates a node with valid service endpoints | nodeId=<EXISTING_NODE_ID>, serviceEndpoints=[{ipAddressV4:"127.0.0.1", port:50212}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | SUCCESS | Y |
| 2 | Updates a node with multiple valid service endpoints | nodeId=<EXISTING_NODE_ID>, serviceEndpoints=[{ipAddressV4:"127.0.0.1", port:50212}, {ipAddressV4:"127.0.0.2", port:50213}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | SUCCESS | Y |
| 3 | Updates a node with maximum service endpoints (8) | nodeId=<EXISTING_NODE_ID>, serviceEndpoints=8 endpoints, adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | SUCCESS | Y |
| 4 | Cannot update a node with more than maximum service endpoints | nodeId=<EXISTING_NODE_ID>, serviceEndpoints=9 endpoints, adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | INTERNAL_ERROR | Y |
| 5 | Cannot update a node with empty service endpoints list | nodeId=<EXISTING_NODE_ID>, serviceEndpoints=[] , adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | INTERNAL_ERROR | Y |
| 6 | Updates a node with service endpoints containing domain names | nodeId=<EXISTING_NODE_ID>, serviceEndpoints=[{domainName:"grpc.hedera.com", port:443}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | SUCCESS | Y |
| 7 | Fails with invalid service endpoint (missing port) | nodeId=<EXISTING_NODE_ID>, serviceEndpoints=[{ipAddressV4="127.0.0.1"}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with INVALID_ENDPOINT. | Y |
| 8 | Fails with both IP and domain in same service endpoint | nodeId=<EXISTING_NODE_ID>, serviceEndpoints=[{ipAddressV4=<VALID_HEX_IP_ADDRESS>, domainName="service.example.com", port=50212}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | INTERNAL_ERROR | Y |
| 9 | Fails with invalid IP address format in service endpoint | nodeId=<EXISTING_NODE_ID>, serviceEndpoints=[{ipAddressV4=<INVALID_HEX_IP_ADDRESS>, port=50212}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with INVALID_ENDPOINT. | Y |
| 10 | Fails with invalid port number (negative) in service endpoint | nodeId=<EXISTING_NODE_ID>, serviceEndpoints=[{ipAddressV4=<VALID_HEX_IP_ADDRESS>, port=-1}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | INTERNAL_ERROR | Y |
| 11 | Fails with invalid port number (too high) in service endpoint | nodeId=<EXISTING_NODE_ID>, serviceEndpoints=[{ipAddressV4=<VALID_HEX_IP_ADDRESS>, port=65536}], adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with INVALID_ENDPOINT. | Y |
GossipCaCertificate:
- Tests the gossip CA certificate parameter
| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---|---|---|---|---|
| 1 | Updates a node with a valid gossip CA certificate | nodeId=<EXISTING_NODE_ID>, gossipCaCertificate=<VALID_DER_CERTIFICATE>, adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signer=[<CREATED_ACCOUNT_PRIVATE_KEY>] | SUCCESS | Y |
| 2 | Cannot update a node with an empty gossip CA certificate | nodeId=<EXISTING_NODE_ID>, gossipCaCertificate="", adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signer=[<CREATED_ACCOUNT_PRIVATE_KEY>] | INTERNAL_ERROR | Y |
| 3 | Cannot update a node with an invalid gossip CA certificate format | nodeId=<EXISTING_NODE_ID>, gossipCaCertificate="invalid_certificate_format", adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signer=[<CREATED_ACCOUNT_PRIVATE_KEY>] | INTERNAL_ERROR | Y |
| 4 | Fails with malformed hex string | nodeId=<EXISTING_NODE_ID>, gossipCaCertificate="not_hex_string", adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signer=[<CREATED_ACCOUNT_PRIVATE_KEY>] | INTERNAL_ERROR | Y |
GrpcCertificateHash:
- Tests the gRPC certificate hash parameter
| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---|---|---|---|---|
| 1 | Update a node with valid gRPC certificate hash | nodeId=<EXISTING_NODE_ID>, grpcCertificateHash="a1b2c3d4e5f6", adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds. | Y |
| 2 | Fails with empty certificate hash | nodeId=<EXISTING_NODE_ID>, grpcCertificateHash="", adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with INVALID_GRPC_CERTIFICATE_HASH. | Y |
| 3 | Cannot update a node with an invalid gRPC certificate hash format | nodeId=<EXISTING_NODE_ID>, grpcCertificateHash="invalid_hash_format" | INTERNAL_ERROR. | Y |
| 4 | Fails with malformed hex string | nodeId=<EXISTING_NODE_ID>, grpcCertificateHash="not_hex_string", adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | INTERNAL_ERROR. | Y |
GrpcWebProxyEndpoint:
- Tests the gRPC web proxy endpoint parameter
| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---|---|---|---|---|
| 1 | Update a node with gRPC web proxy endpoint | nodeId=<EXISTING_NODE_ID>, grpcWebProxyEndpoint={ipAddressV4=<VALID_HEX_IP_ADDRESS>, port=50213}, adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update fails with INVALID_SERVICE_ENDPOINT. | Y |
| 2 | Update a node with domain-based gRPC web proxy endpoint | nodeId=<EXISTING_NODE_ID>, grpcWebProxyEndpoint={domainName="proxy.example.com", port=50213}, adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds. | Y |
| 3 | Deletes a gRPC web proxy endpoint | nodeId=<EXISTING_NODE_ID>, grpcWebProxyEndpoint={}, adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | SUCCESS | Y |
AdminKey:
| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---|---|---|---|---|
| 1 | Update a node with valid ED25519 public key as admin key | nodeId=<EXISTING_NODE_ID>, adminKey=<VALID_ED25519_PUBLIC_KEY>, commonTransactionParams.signers=[<CORRESPONDING_ED25519_PRIVATE_KEY>] | The node update succeeds. | Y |
| 2 | Update a node with valid ECDSAsecp256k1 public key as admin key | nodeId=<EXISTING_NODE_ID>, adminKey=<VALID_ECDSA_SECP256K1_PUBLIC_KEY>, commonTransactionParams.signers=[<CORRESPONDING_ECDSA_SECP256K1_PRIVATE_KEY>] | The node update succeeds. | Y |
| 3 | Update a node with valid ED25519 private key as admin key | nodeId=<EXISTING_NODE_ID>, adminKey=<VALID_ED25519_PRIVATE_KEY>, commonTransactionParams.signers=[<CORRESPONDING_ED25519_PRIVATE_KEY>] | The node update succeeds. | Y |
| 4 | Update a node with valid ECDSAsecp256k1 private key as admin key | nodeId=<EXISTING_NODE_ID>, adminKey=<VALID_ECDSA_SECP256K1_PRIVATE_KEY>, commonTransactionParams.signers=[<CORRESPONDING_ECDSA_SECP256K1_PRIVATE_KEY>] | The node update succeeds. | Y |
| 5 | Update a node with valid KeyList of ED25519 and ECDSAsecp256k1 keys as admin key | nodeId=<EXISTING_NODE_ID>, adminKey=<VALID_KEYLIST>, commonTransactionParams.signers=[<CORRESPONDING_ED25519_PRIVATE_KEY>] | The node update succeeds. | Y |
| 6 | Update a node with valid nested KeyList (three levels) as admin key | nodeId=<EXISTING_NODE_ID>, adminKey=<VALID_NESTED_KEYLIST>, commonTransactionParams.signers=[<CORRESPONDING_ED25519_PRIVATE_KEY>] | The node update succeeds. | Y |
| 7 | Update a node with valid ThresholdKey of ED25519 and ECDSAsecp256k1 keys as admin key | nodeId=<EXISTING_NODE_ID>, adminKey=<VALID_THRESHOLD_KEY>, commonTransactionParams.signers=[<CORRESPONDING_ED25519_PRIVATE_KEY>] | The node update succeeds. | Y |
| 8 | Fails with valid admin key without signing with the new key | nodeId=<EXISTING_NODE_ID>, adminKey=<VALID_KEY> | The node update fails with an INVALID_SIGNATURE response code. | Y |
| 9 | Fails with invalid admin key format | nodeId=<EXISTING_NODE_ID>, adminKey="invalid_key", commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | INTERNAL_ERROR | Y |
DeclineReward:
| Test no | Name | Input | Expected response | Implemented (Y/N) |
|---|---|---|---|---|
| 1 | Update a node that accepts rewards (default) | nodeId=<EXISTING_NODE_ID>, adminKey=<CREATED_ADMIN_KEY>, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds. | Y |
| 2 | Update a node that declines rewards | nodeId=<EXISTING_NODE_ID>, adminKey=<CREATED_ADMIN_KEY>, declineReward=true, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds. | Y |
| 3 | Update a node with explicit declineReward: false | nodeId=<EXISTING_NODE_ID>, adminKey=<CREATED_ADMIN_KEY>, declineReward=false, commonTransactionParams.signers=[<CREATED_ACCOUNT_PRIVATE_KEY>] | The node update succeeds. | Y |