The attribute has uint32 data inside which is the block height starting from
which the transaction is considered to be valid. It can be seen as the opposite
of `ValidUntilBlock`, using both allows to have a window of valid block numbers
that this transaction could be accepted into. Transactions with this attribute
are not accepted into mempool before specified block is persisted.
It can be used to create some transactions in advance with a guarantee that they
won't be accepted until specified block.
#### NotaryAssisted
This attribute contains one byte containing the number of transactions collected
by the service. It could be 0 for fallback transaction or `NKeys` for normal
transaction that completed its P2P signature collection. Transactions using this
attribute need to pay an additional network fee of (`NKeys`+1)×`FEE`. This attribute
could be only be used by transactions signed by the notary native contract.
### Native Notary contract
It exposes several methods to the outside world:
| Method | Parameters | Return value | Description |
| --- | --- | --- | --- |
| `onNEP17Payment` | `from` (uint160) - GAS sender account.<br>`amount` (int) - amount of GAS to deposit.<br>`data` represents array of two parameters: <br>1. `to` (uint160) - account of the deposit owner.<br>2. `till` (int) - deposit lock height. | `bool` | Automatically called after GAS transfer to Notary native contract address and records deposited amount as belonging to `to` address with a lock till `till` chain's height. Can only be invoked from native GAS contract. Must be witnessed by `from`. `to` can be left unspecified (null), with a meaning that `to` is the same address as `from`. `amount` can't be less than 2×`FEE` for the first deposit call for the `to` address. Each successive deposit call must have `till` value equal to or more than the previous successful call (allowing for renewal), if it has additional amount of GAS it adds up to the already deposited value.|
| `lockDepositUntil` | `address` (uint160) - account of the deposit owner.<br>`till` (int) - new height deposit is valid until (can't be less than previous value). | `void` | Updates deposit expiration value. Must be witnessed by `address`. |
| `withdraw` | `from` (uint160) - account of the deposit owner.<br>`to` (uint160) - account to transfer GAS to. | `bool` | Sends all deposited GAS for `from` address to `to` address. Must be witnessed by `from`. `to` can be left unspecified (null), with a meaning that `to` is the same address as `from`. It can only be successful if the lock has already expired, attempting to withdraw the deposit before that height fails. Partial withdrawal is not supported. Returns boolean result, `true` for successful calls and `false` for failed ones. |
| `balanceOf` | `addr` (uint160) - account of the deposit owner. | `int` | Returns deposited GAS amount for specified address (integer). |
| `expirationOf` | `addr` (uint160) - account of the deposit owner. | `int` | Returns deposit lock height for specified address (integer). |
| `verify` | `signature` (signature) - notary node signature bytes for verification. | `bool` | This is used to verify transactions with notary contract specified as a signer, it needs one signature in the invocation script and it checks for this signature to be made by one of designated keys, effectively implementing "1 out of N" multisignature contract. |
| `getMaxNotValidBeforeDelta` | | `int` | Returns `MaxNotValidBeforeDelta` constraint. Default value is 140. |
| `setMaxNotValidBeforeDelta` | `value` (int) | `void` | Set `MaxNotValidBeforeDelta` constraint. Must be witnessed by committee. |
See the [Notary deposit guide](#1.-Notary-deposit) section on how to deposit
funds to Notary native contract and manage the deposit.
### P2PNotaryRequest payload
A new broadcasted payload type is introduced for notary requests. It's
distributed via regular inv-getdata mechanism like transactions, blocks or
consensus payloads. An ordinary P2P node verifies it, saves in a structure
similar to mempool and relays. This payload has witness (standard
single-signature contract) attached signing all of the payload.
This payload has two incomplete transactions inside:
- *Fallback tx*. This transaction has P2P Notary contract as a sender and service
request sender as an additional signer. It can't have a witness for Notary
contract, but it must have proper witness for request sender. It must have
`NotValidBefore` attribute that is no more than `MaxNotValidBeforeDelta` higher
than the current chain height and it must have `Conflicts` attribute with the
hash of the main transaction. It at the same time must have `Notary assisted`
10. Define lifetime for the fallback transaction. Let the `fallbackValidFor` be
the lifetime. Let `N` be the current chain's height and `VUB` be
`ValidUntilBlock` value estimated at the step 3. Then notary node is trying to
collect signatures for the main transaction from `N` up to
`VUB-fallbackValidFor`. In case of failure after `VUB-fallbackValidFor`-th
block is accepted, notary node stops attempts to complete main transaction and
tries to push all associated fallbacks. Use the following rules to define
`fallbackValidFor`:
-`fallbackValidFor` shouldn't be more than `MaxNotValidBeforeDelta` value.
- Use [func (*Client) GetMaxNotValidBeforeDelta](https://pkg.go.dev/github.com/nspcc-dev/neo-go@v0.97.2/pkg/rpc/client#Client.GetMaxNotValidBeforeDelta)
to check `MaxNotValidBefore` value.
11. Construct script for the fallback transaction. Script may do something useful,
i.g. invoke method of a contract, but if you don't need to perform something
special on fallback invocation, you can use simple `opcode.RET` script.
12. Sign and submit P2P notary request. Use
[func (*Client) SignAndPushP2PNotaryRequest](https://pkg.go.dev/github.com/nspcc-dev/neo-go@v0.97.2/pkg/rpc/client#Client.SignAndPushP2PNotaryRequest) for it.
- Use signed main transaction from step 8 as `mainTx` argument.
- Use fallback script from step 10 as `fallbackScript` argument.
- Use `-1` as `fallbackSysFee` argument to define system fee by test
invocation or provide custom value.
- Use `0` as `fallbackNetFee` argument not to add extra network fee to the
fallback.
- Use `fallbackValidFor` estimated at step 9 as `fallbackValidFor` argument.
- Use your account you'd like to send request (and fallback transaction) from
to sign the request (and fallback transaction).
`SignAndPushP2PNotaryRequest` will construct and sign fallback transaction,
construct and sign P2PNotaryRequest and submit it to the RPC node. The
resulting notary request and an error are returned.
After P2PNotaryRequests are sent, participants should then wait for one of their
transactions (main or fallback) to get accepted into one of subsequent blocks.
### 3. Signatures collection and transaction release
Valid P2PNotaryRequest payload is distributed via P2P network using standard
broadcasting mechanisms until it reaches designated notary nodes that have the
respective node module active. They collect all payloads for the same main
transaction until enough signatures are collected to create proper witnesses for
it. They then attach all witnesses required and send this transaction as usual
and monitor subsequent blocks for its inclusion.
All the operations leading to successful transaction creation are independent
of the chain and could easily be done within one block interval, so if the
first service request is sent at current height `H` it's highly likely that the
main transaction will be a part of `H+1` block.
### 4. Results monitoring
Once P2PNotaryRequest reached RPC node, it is added to the notary request pool.
Completed or outdated requests are being removed from the pool. Use
[NeoGo notification subsystem](./notifications.md) to track request addition and
removal:
- Use RPC `subscribe` method with `notary_request_event` stream name parameter to
subscribe to `P2PNotaryRequest` payloads that are added or removed from the
notary request pool.
- Use `sender` or `signer` filters to filter out notary request with desired
request senders or main tx signers.
Use the notification subsystem to track that main or fallback transaction
accepted to the chain:
- Use RPC `subscribe` method with `transaction_added` stream name parameter to
subscribe to transactions that are accepted to the chain.
- Use `sender` filter with Notary native contract hash to filter out fallback
transactions sent by Notary node. Use `signer` filter with notary request
sender address to filter out fallback transactions sent by the specified
sender.
- Use `sender` or `signer` filters to filter out main transaction with desired
sender or signers. You can also filter out main transaction using Notary
contract `signer` filter.
- Don't rely on `sender` and `signer` filters only, check also that received
transaction has `NotaryAssisted` attribute with expected `NKeys` value.
Use the notification subsystem to track main or fallback transaction execution
results.
Moreover, you can use all regular RPC calls to track main or fallback transaction
invocation: `getrawtransaction`, `getapplicationlog` etc.
## Notary service use-cases
Several use-cases where Notary subsystem can be applied are described below.
### Committee-signed transactions
The signature collection problem occures every time committee participants need
to submit transaction with `m out of n` multisignature, i.g.:
- transfer initial supply of NEO and GAS from committee multisignature account to
other addresses on new chain start
- tune valuable chain parameters like gas per block, candidate register price,