forked from TrueCloudLab/neoneo-go
rpcclient: support getrawnotarytransaction and getrawnotarypool RPC methods
GetRawNotaryTransaction returns a fallback or main transaction that was previously added to the memory pool by P2PNotaryRequest. This function invokes the RPC server's `getrawnotarytransaction` method. GetRawNotaryPool returns hashes from all the verified transactions, including both main and fallback transactions. This function invokes the RPC server's `getrawnotarypool` method. Also, these functions were added to doc.go. Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
This commit is contained in:
parent
9e31e42bd9
commit
d06f135792
4 changed files with 257 additions and 0 deletions
|
@ -96,6 +96,8 @@ Supported methods
|
|||
Extensions:
|
||||
|
||||
getblocksysfee
|
||||
getrawnotarypool
|
||||
getrawnotarytransaction
|
||||
submitnotaryrequest
|
||||
|
||||
Unsupported methods
|
||||
|
|
|
@ -1285,3 +1285,44 @@ func (c *Client) TerminateSession(sessionID uuid.UUID) (bool, error) {
|
|||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetRawNotaryTransaction returns main or fallback transaction from the
|
||||
// RPC node's notary request pool.
|
||||
func (c *Client) GetRawNotaryTransaction(hash util.Uint256) (*transaction.Transaction, error) {
|
||||
var (
|
||||
params = []any{hash.StringLE()}
|
||||
resp []byte
|
||||
err error
|
||||
)
|
||||
if err = c.performRequest("getrawnotarytransaction", params, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transaction.NewTransactionFromBytes(resp)
|
||||
}
|
||||
|
||||
// GetRawNotaryTransactionVerbose returns main or fallback transaction from the
|
||||
// RPC node's notary request pool.
|
||||
// NOTE: to get transaction.ID and transaction.Size, use t.Hash() and
|
||||
// io.GetVarSize(t) respectively.
|
||||
func (c *Client) GetRawNotaryTransactionVerbose(hash util.Uint256) (*transaction.Transaction, error) {
|
||||
var (
|
||||
params = []any{hash.StringLE(), 1} // 1 for verbose.
|
||||
resp = &transaction.Transaction{}
|
||||
err error
|
||||
)
|
||||
if err = c.performRequest("getrawnotarytransaction", params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetRawNotaryPool returns hashes of main P2PNotaryRequest transactions that
|
||||
// are currently in the RPC node's notary request pool with the corresponding
|
||||
// hashes of fallback transactions.
|
||||
func (c *Client) GetRawNotaryPool() (*result.RawNotaryPool, error) {
|
||||
resp := &result.RawNotaryPool{}
|
||||
if err := c.performRequest("getrawnotarypool", nil, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
|
|
@ -1375,6 +1375,89 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
},
|
||||
},
|
||||
},
|
||||
"getrawnotarytransaction": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
hash, err := util.Uint256DecodeStringLE("ad1c2875de823a54188949490e2d68580fd070fcc5ff409609f478d23d12355f")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return c.GetRawNotaryTransaction(hash)
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":"AAMAAAAAAAAAAAAAAAAAAAAAAAAAewAAAAHunqIsJ+NL0BSPxBCOCPdOj1BIsgABIgEBQAEDAQQHAwMGCQ=="}`,
|
||||
result: func(c *Client) any {
|
||||
return &transaction.Transaction{}
|
||||
},
|
||||
check: func(t *testing.T, c *Client, uns any) {
|
||||
res, ok := uns.(*transaction.Transaction)
|
||||
require.True(t, ok)
|
||||
assert.NotNil(t, res)
|
||||
expectHash, err := util.Uint256DecodeStringLE("ad1c2875de823a54188949490e2d68580fd070fcc5ff409609f478d23d12355f")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expectHash, res.Hash())
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "positive verbose",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
hash, err := util.Uint256DecodeStringLE("ad1c2875de823a54188949490e2d68580fd070fcc5ff409609f478d23d12355f")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return c.GetRawNotaryTransactionVerbose(hash)
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"hash":"0xad1c2875de823a54188949490e2d68580fd070fcc5ff409609f478d23d12355f","size":61,"version":0,"nonce":3,"sender":"Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn","sysfee":"0","netfee":"0","validuntilblock":123,"attributes":[{"nkeys":1,"type":"NotaryAssisted"}],"signers":[{"account":"0xb248508f4ef7088e10c48f14d04be3272ca29eee","scopes":"None"}],"script":"QA==","witnesses":[{"invocation":"AQQH","verification":"AwYJ"}]}}`,
|
||||
result: func(c *Client) any {
|
||||
return &transaction.Transaction{}
|
||||
},
|
||||
check: func(t *testing.T, c *Client, uns any) {
|
||||
res, ok := uns.(*transaction.Transaction)
|
||||
require.True(t, ok)
|
||||
assert.NotNil(t, res)
|
||||
expectHash, err := util.Uint256DecodeStringLE("ad1c2875de823a54188949490e2d68580fd070fcc5ff409609f478d23d12355f")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expectHash, res.Hash())
|
||||
},
|
||||
},
|
||||
},
|
||||
"getrawnotarypool": {
|
||||
{
|
||||
name: "empty pool",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetRawNotaryPool()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{}}`,
|
||||
result: func(c *Client) any {
|
||||
return &result.RawNotaryPool{
|
||||
Hashes: map[util.Uint256][]util.Uint256{},
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nonempty pool",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetRawNotaryPool()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"hashes":{"0xd86b5346e9bbe6dba845cc4192fa716535a3d05c4f2084431edc99dc3862a299":["0xbb0b2f1d5539dd776637f00e5011d97921a1400d3a63c02977a38446180c6d7c"]}}}`,
|
||||
result: func(c *Client) any {
|
||||
return &result.RawNotaryPool{
|
||||
Hashes: map[util.Uint256][]util.Uint256{},
|
||||
}
|
||||
},
|
||||
check: func(t *testing.T, c *Client, uns any) {
|
||||
res, ok := uns.(*result.RawNotaryPool)
|
||||
require.True(t, ok)
|
||||
mainHash, err := util.Uint256DecodeStringLE("d86b5346e9bbe6dba845cc4192fa716535a3d05c4f2084431edc99dc3862a299")
|
||||
require.NoError(t, err, "can't decode `mainHash` result hash")
|
||||
fallbackHash, err := util.Uint256DecodeStringLE("bb0b2f1d5539dd776637f00e5011d97921a1400d3a63c02977a38446180c6d7c")
|
||||
require.NoError(t, err, "can't decode `fallbackHash` result hash")
|
||||
fallbacks, ok := res.Hashes[mainHash]
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, fallbacks[0], fallbackHash)
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type rpcClientErrorCase struct {
|
||||
|
|
|
@ -1135,6 +1135,137 @@ func TestSignAndPushP2PNotaryRequest(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestGetRawNotaryPoolAndTransaction(t *testing.T) {
|
||||
var (
|
||||
mainHash1, fallbackHash1, mainHash2, fallbackHash2 util.Uint256
|
||||
tx1, tx2 *transaction.Transaction
|
||||
)
|
||||
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChainAndServices(t, false, true, false)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
t.Run("getrawnotarypool", func(t *testing.T) {
|
||||
t.Run("empty pool", func(t *testing.T) {
|
||||
np, err := c.GetRawNotaryPool()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(np.Hashes))
|
||||
})
|
||||
|
||||
sender := testchain.PrivateKeyByID(0) // owner of the deposit in testchain
|
||||
acc := wallet.NewAccountFromPrivateKey(sender)
|
||||
|
||||
comm, err := c.GetCommittee()
|
||||
require.NoError(t, err)
|
||||
|
||||
multiAcc := &wallet.Account{}
|
||||
*multiAcc = *acc
|
||||
require.NoError(t, multiAcc.ConvertMultisig(smartcontract.GetMajorityHonestNodeCount(len(comm)), comm))
|
||||
|
||||
nact, err := notary.NewActor(c, []actor.SignerAccount{{
|
||||
Signer: transaction.Signer{
|
||||
Account: multiAcc.Contract.ScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: multiAcc,
|
||||
}}, acc)
|
||||
require.NoError(t, err)
|
||||
neoW := neo.New(nact)
|
||||
// Send the 1st notary request
|
||||
tx1, err = neoW.SetRegisterPriceTransaction(1_0000_0000)
|
||||
require.NoError(t, err)
|
||||
mainHash1, fallbackHash1, _, err = nact.Notarize(tx1, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
checkTxInPool := func(t *testing.T, mainHash, fallbackHash util.Uint256, res *result.RawNotaryPool) {
|
||||
actFallbacks, ok := res.Hashes[mainHash]
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, 1, len(actFallbacks))
|
||||
require.Equal(t, fallbackHash, actFallbacks[0])
|
||||
}
|
||||
t.Run("nonempty pool", func(t *testing.T) {
|
||||
actNotaryPool, err := c.GetRawNotaryPool()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(actNotaryPool.Hashes))
|
||||
checkTxInPool(t, mainHash1, fallbackHash1, actNotaryPool)
|
||||
})
|
||||
|
||||
// Send the 2nd notary request
|
||||
tx2, err = neoW.SetRegisterPriceTransaction(2_0000_0000)
|
||||
require.NoError(t, err)
|
||||
mainHash2, fallbackHash2, _, err = nact.Notarize(tx2, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("pool with 2", func(t *testing.T) {
|
||||
actNotaryPool, err := c.GetRawNotaryPool()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(actNotaryPool.Hashes))
|
||||
checkTxInPool(t, mainHash1, fallbackHash1, actNotaryPool)
|
||||
checkTxInPool(t, mainHash2, fallbackHash2, actNotaryPool)
|
||||
})
|
||||
})
|
||||
t.Run("getrawnotarytransaction", func(t *testing.T) {
|
||||
t.Run("client GetRawNotaryTransaction", func(t *testing.T) {
|
||||
t.Run("unknown transaction", func(t *testing.T) {
|
||||
_, err := c.GetRawNotaryTransaction(util.Uint256{0, 0, 0})
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, neorpc.ErrUnknownTransaction)
|
||||
})
|
||||
_ = tx1.Size()
|
||||
_ = tx2.Size()
|
||||
// RPC server returns empty scripts in transaction.Witness,
|
||||
// thus here the nil-value was changed to empty value.
|
||||
if tx1.Scripts[1].InvocationScript == nil && tx1.Scripts[1].VerificationScript == nil {
|
||||
tx1.Scripts[1] = transaction.Witness{
|
||||
InvocationScript: []byte{},
|
||||
VerificationScript: []byte{},
|
||||
}
|
||||
}
|
||||
if tx2.Scripts[1].InvocationScript == nil && tx2.Scripts[1].VerificationScript == nil {
|
||||
tx2.Scripts[1] = transaction.Witness{
|
||||
InvocationScript: []byte{},
|
||||
VerificationScript: []byte{},
|
||||
}
|
||||
}
|
||||
t.Run("transactions from pool", func(t *testing.T) {
|
||||
mainTx1, err := c.GetRawNotaryTransaction(mainHash1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tx1, mainTx1)
|
||||
_, err = c.GetRawNotaryTransaction(fallbackHash1)
|
||||
require.NoError(t, err)
|
||||
|
||||
mainTx2, err := c.GetRawNotaryTransaction(mainHash2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tx2, mainTx2)
|
||||
_, err = c.GetRawNotaryTransaction(fallbackHash2)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
})
|
||||
t.Run("client GetRawNotaryTransactionVerbose", func(t *testing.T) {
|
||||
t.Run("unknown transaction", func(t *testing.T) {
|
||||
_, err := c.GetRawNotaryTransactionVerbose(util.Uint256{0, 0, 0})
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, neorpc.ErrUnknownTransaction)
|
||||
})
|
||||
t.Run("transactions from pool", func(t *testing.T) {
|
||||
mainTx1, err := c.GetRawNotaryTransactionVerbose(mainHash1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tx1, mainTx1)
|
||||
_, err = c.GetRawNotaryTransactionVerbose(fallbackHash1)
|
||||
require.NoError(t, err)
|
||||
|
||||
mainTx2, err := c.GetRawNotaryTransactionVerbose(mainHash2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tx2, mainTx2)
|
||||
_, err = c.GetRawNotaryTransactionVerbose(fallbackHash2)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestCalculateNotaryFee(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
|
|
Loading…
Reference in a new issue