Compare commits

...

877 commits

Author SHA1 Message Date
Anna Shaleva
b66cea5ccc
Merge pull request #3483 from nspcc-dev/bump-neofs-sdk
go.mod: update NeoFS SDK to RC12
2024-06-07 16:37:04 +03:00
Roman Khimov
e5eb20bbae go.mod: update NeoFS SDK to RC12
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-06-07 15:08:25 +03:00
Anna Shaleva
cf4d4a2611
Merge pull request #3469 from nspcc-dev/warn
logs: distinguish WARN and INFO for `peer disconnected`
2024-06-05 15:39:52 +03:00
Anna Shaleva
7a7a5d0322
Merge pull request #3470 from nspcc-dev/contract-acc
wallet: do not store deployed contract script inside `Contract` account field
2024-06-05 15:35:04 +03:00
Ekaterina Pavlova
4d6333866d network: extend errInvalidInvType error
Add type to the errInvalidInvType.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-06-05 15:32:43 +03:00
Ekaterina Pavlova
4a5e8f8592 logs: distinguish WARN and INFO for peer disconnected
Peer disconnections are not warnings in some cases.

Close #3182

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-06-05 15:32:42 +03:00
Ekaterina Pavlova
b4fdf8c3c9 wallet: do not store deployed contract script inside Contract account
`Contract` account field should not contain deployed contract script.

Close #3348

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-06-05 15:27:20 +03:00
Anna Shaleva
3c471f0b7e
Merge pull request #3455 from nspcc-dev/sast
Adjust minor SAST warnings
2024-06-05 12:21:42 +03:00
Ekaterina Pavlova
41109f442a oracle: add length check o.MainCfg.NeoFS.Nodes
Prevent the risk of a division by zero error when accessing the
`o.MainCfg.NeoFS.Nodes[index]` array.

Close #3419

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-06-05 11:53:52 +03:00
Ekaterina Pavlova
5c408f7fe4 core: adjust prevHeader nil check
prevHeader is never nil.

Refs #3419

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-06-05 11:53:52 +03:00
Anna Shaleva
cd525a1df5
Merge pull request #3468 from nspcc-dev/logs
logs: hide timestamp if the program is run not in TTY
2024-06-05 10:46:13 +03:00
Roman Khimov
836183ecb6
Merge pull request #3475 from nspcc-dev/rel-0.106.1 2024-06-03 17:15:44 +03:00
Anna Shaleva
3c1c650ddf CHANGELOG: release 0.106.1
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-06-03 16:12:36 +03:00
Anna Shaleva
45b8af359d
Merge pull request #3472 from nspcc-dev/pick-proper-exe-context
interop: use executing contract state for permissions checks
2024-06-03 16:10:39 +03:00
Anna Shaleva
4945145b09 interop: use executing contract state for permissions checks
Do not use the updated contract state from native Management to perform
permissions checks. We need to use the currently executing state
instead got from the currently executing VM context until context is
unloaded.

Close #3471.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-06-03 12:32:10 +03:00
Ekaterina Pavlova
f48e992a78 logs: hide timestamp if the program is run not in TTY
If the program is run in TTY then logger adds timestamp to its entries.

Close #3358

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-06-03 11:49:54 +03:00
Roman Khimov
0b136c1c9c
Merge pull request #3463 from nspcc-dev/fool-protection 2024-05-25 00:59:23 +03:00
Anna Shaleva
f4aeaa6387 workflows: protect go.mod from unexpected imports
Avoid situations like #3458.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-24 21:11:39 +03:00
Roman Khimov
0ae5e7ea83
Merge pull request #3458 from nspcc-dev/remove-contract-deps
go.mod: remove unused dependency
2024-05-21 21:46:15 +03:00
Anna Shaleva
228052360e go.mod: remove unused dependency
Was accidentally added in
aa5a0cb49b.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-21 20:40:38 +03:00
Roman Khimov
5cbfe215a4
Merge pull request #3453 from nspcc-dev/rel-0.106.0
CHANGELOG: release 0.106.0
2024-05-21 15:48:52 +03:00
Anna Shaleva
72161fe902 CHANGELOG: release 0.106.0
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-21 15:44:22 +03:00
Anna Shaleva
aceaabe9d6 ROADMAP: update roadmap
Reschedule deprecated functionality removal for 0.107.0 release.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-21 14:26:05 +03:00
Anna Shaleva
9ba532ce9c docs: adjust release instructions
Add a note about checking NeoFS networks for compatibility.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-21 14:26:05 +03:00
Roman Khimov
2aa3c93acd
Merge pull request #3452 from nspcc-dev/p2pnotary-role
core: move P2PNotary node role out of P2PSigExtensions
2024-05-21 13:53:52 +03:00
Anna Shaleva
aa5a0cb49b *: update interop deps
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-21 12:36:51 +03:00
Anna Shaleva
7868578571 core: move P2PNotary node role out of P2PSigExtensions
Port https://github.com/neo-project/neo/pull/3172.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-21 12:10:47 +03:00
Roman Khimov
6a5833759c
Merge pull request #3448 from nspcc-dev/migrate-to-hf
Bind 0.106.0 protocol chages to Cockatrice hardfork
2024-05-20 15:51:26 +03:00
Roman Khimov
6be757af3e
Merge pull request #3444 from nspcc-dev/fix-native-init
native: perform initialisation for the set of hardforks
2024-05-17 16:34:00 +03:00
Roman Khimov
67b6d5da31
Merge pull request #3446 from nspcc-dev/enable-cockatrice
config: enable Cockatrice hardfork
2024-05-17 16:33:16 +03:00
Anna Shaleva
b5bb605651
Merge pull request #3443 from nspcc-dev/fix-blocked-accounts
native: fix Policy's IsBlocked behaviour
2024-05-17 16:10:59 +03:00
Anna Shaleva
d91a0945df config: enable Cockatrice hardfork
Close #3434.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-17 16:01:48 +03:00
Anna Shaleva
c90f6785b9 native: perform initialisation for the set of hardforks
Close #3433.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-17 15:58:02 +03:00
Anna Shaleva
c30e7ec8d7 native: bind CryptoLib's verifyWithECDsa changes to Cockatrice
A part of #3440.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-17 15:52:00 +03:00
Anna Shaleva
ce442a1942 rpcsrv: remove test for Koblitz-based witness verification
It will be built properly in #3447.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-17 15:45:04 +03:00
Anna Shaleva
e92606a7ae native: bind Neo's CommitteeChanged event to Cockatrice
A part of #3440.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-17 15:22:29 +03:00
Anna Shaleva
df1ed68d98 native: support native method/event removal
Port a part of https://github.com/neo-project/neo/issues/3210.
A part of #3440.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-17 15:22:26 +03:00
Anna Shaleva
82a7c1bd9c native: adjust test helper behaviour
Supply the account with expected balance.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-17 12:33:59 +03:00
Anna Shaleva
c43cfae24c native: fix Policy's IsBlocked behaviour
Account is blocked when it's in the Policy's storage, not when it's
missing from the Policy storage. Introduced in
bbbc6805a8.

This bug leads to the fact that during native Neo cache initialization
at the last block in the dBFT epoch, all candidates accounts are
"blocked", and thus, stand-by committee and validators are used in the
subsequent new epoch. Close #3424.

This bug may lead to the consequences described in #3273, but it needs
to be confirmed.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-17 12:33:51 +03:00
Anna Shaleva
2d4993a837
Merge pull request #3438 from nspcc-dev/unwrap-fault-exception
unwrap: implement Exception type for better exception handling
2024-05-17 10:24:26 +03:00
Anna Shaleva
647b8c7fb1
Merge pull request #3439 from nspcc-dev/getnativecontracts
state: drop NativeContract, fix #3430
2024-05-17 10:23:45 +03:00
Roman Khimov
0b69901d1e
Merge pull request #3441 from nspcc-dev/boltdb-clone 2024-05-16 19:49:11 +03:00
Roman Khimov
502f024e7c storage: bytes.Clone(nil) == nil
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-05-16 19:29:11 +03:00
Roman Khimov
b1bb12df48 state: drop NativeContract, fix #3430
This unifies getnativecontracts RPC API with regular contracts.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-05-16 18:46:46 +03:00
Roman Khimov
31a99d44eb
Merge pull request #3437 from nspcc-dev/fix-conflicts 2024-05-16 13:38:03 +03:00
Anna Shaleva
dc8b2f639a dao: do not remove block executable by conflict record stub
It's possible for transaction to include block hash into Conflicts
attribure. If so, then we must not remove block executable record while
cleaning transation's conflict records.

This commit is a direct consequence of
e6ceee0f230a21c87006a9297636be29c0d8ea47. Ref. #3427.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-16 12:13:41 +03:00
Anna Shaleva
2ad4c86712 dao: move conflict record value length to a separate const
Conflicts-related code contains more and more these magic numbers, and
there's no good in it even if all the usages are commented. This
approach produces bugs like #3426.

No functional changes, just a refactoring.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-16 12:13:41 +03:00
Anna Shaleva
9a1075d332 dao: fix transaction application log decoding
Conflict record stub has value of 5 bytes length: 1 byte for
storage.ExecTransaction prefix and 4 bytes for the block index LE. This
scheme was implemented in #3138, and this commit should be a part of
this PR.

Also, transaction.DummyVersion is removed since it's unused anymore.

Close #3426. The reason of `failed to locate application log: EOF` error
during genesis AER request is in the following: genesis executable was
overwritten by conflict record stub produced by transaction
0x289c235dcdab8be7426d05f0fbb5e86c619f81481ea136493fa95deee5dbb7cc (ref.
 #3427). As a consequence, an attempt to decode transaction AER was
initited, but conflict record scheme was changed in #3138.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-16 12:13:41 +03:00
Anna Shaleva
58a086ea91 core: allow transaction to conflict with block
Transaction
0x289c235dcdab8be7426d05f0fbb5e86c619f81481ea136493fa95deee5dbb7cc is
already on mainnet at block 5272006 and we can't do anything with it.
This transaction has genesis block hash in Conflicts attribute. It leads
to the following consequences:
1. Genesis block executable record is overwritten by conflict record
   stub. Genesis block can't be retrieved anymore. This bug is described
   in #3427.
2. Somehow this transaction has passed verification on NeoGo CN without
   any warnings:
```
Apr 24 16:12:30 kangra neo-go[2453907]: 2024-04-24T16:12:30.865+0300        INFO        initializing dbft        {"height": 5272006, "view": 0, "index": 6, "role": "Backup"}
Apr 24 16:12:31 kangra neo-go[2453907]: 2024-04-24T16:12:31.245+0300        INFO        persisted to disk        {"blocks": 1, "keys": 37, "headerHeight": 5272005, "blockHeight": 5272005, "took": "14.548903ms"}
Apr 24 16:12:34 kangra neo-go[2453907]: 2024-04-24T16:12:34.977+0300        ERROR        can't add SV-signed state root        {"error": "stateroot mismatch at block 5272005: 9d5f95784f26c862d6f889f213aad1e3330611880c02330e88db8802c750aa46 vs d25304d518645df725014897d13bbf023919928e79074abcea48f31cf9f32a25"}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.820+0300        INFO        received PrepareRequest        {"validator": 5, "tx": 1}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.821+0300        INFO        sending PrepareResponse        {"height": 5272006, "view": 0}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.827+0300        INFO        received PrepareResponse        {"validator": 4}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.830+0300        INFO        received PrepareResponse        {"validator": 3}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.875+0300        INFO        received PrepareResponse        {"validator": 2}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.878+0300        INFO        sending Commit        {"height": 5272006, "view": 0}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.879+0300        INFO        received Commit        {"validator": 4}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.881+0300        INFO        received PrepareResponse        {"validator": 0}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.881+0300        INFO        received Commit        {"validator": 3}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.906+0300        INFO        received Commit        {"validator": 0}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.907+0300        INFO        received PrepareResponse        {"validator": 1}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.915+0300        INFO        received Commit        {"validator": 1}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.915+0300        INFO        approving block        {"height": 5272006, "hash": "6b111519537343ce579d04ccad71c43318b12c680d0f374dfcd466aa22643fb6", "tx_count": 1, "merkle": "ccb7dbe5ee5da93f4936a11e48819f616ce8b5fbf0056d42e78babcd5d239c28", "prev": "12ad6cc5d0cd357b9fc9fb0c1a016ba8014d3cdd5a96818598e6a40a1a4a2a21"}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.917+0300        WARN        contract invocation failed        {"tx": "289c235dcdab8be7426d05f0fbb5e86c619f81481ea136493fa95deee5dbb7cc", "block": 5272006, "error": "at instruction 86 (ASSERT): ASSERT failed"}
Apr 24 16:12:45 kangra neo-go[2453907]: 2024-04-24T16:12:45.950+0300        INFO        initializing dbft        {"height": 5272007, "view": 0, "index": 6, "role": "Primary"}
Apr 24 16:12:46 kangra neo-go[2453907]: 2024-04-24T16:12:46.256+0300        INFO        persisted to disk        {"blocks": 1, "keys": 67, "headerHeight": 5272006, "blockHeight": 5272006, "took": "16.576594ms"}
```
   And thus, we must treat this transaction as valid for this behaviour
   to be reproducable.

This commit contains two fixes:
1. Do not overwrite block executable records by conflict record stubs.
   If some transaction conflicts with block, then just skip the conflict
   record stub for this attribute since it's impossible to create
   transaction with the same hash.
2. Do not fail verification for those transactions that have Conflicts
   attribute with block hash inside. This one is controversial, but we
   have to adjust this code to treat already accepted transaction as
   valid.

Close #3427.

The transaction itself:
```
{
   "id" : 1,
   "jsonrpc" : "2.0",
   "result" : {
      "attributes" : [
         {
            "height" : 0,
            "type" : "NotValidBefore"
         },
         {
            "hash" : "0x1f4d1defa46faa5e7b9b8d3f79a06bec777d7c26c4aa5f6f5899a291daa87c15",
            "type" : "Conflicts"
         }
      ],
      "blockhash" : "0xb63f6422aa66d4fc4d370f0d682cb11833c471adcc049d57ce4373531915116b",
      "blocktime" : 1713964365700,
      "confirmations" : 108335,
      "hash" : "0x289c235dcdab8be7426d05f0fbb5e86c619f81481ea136493fa95deee5dbb7cc",
      "netfee" : "237904",
      "nonce" : 0,
      "script" : "CxAMFIPvkoyXujYCRmgq9qEfMJQ4wNveDBSD75KMl7o2AkZoKvahHzCUOMDb3hTAHwwIdHJhbnNmZXIMFPVj6kC8KD1NDgXEjqMFs/Kgc0DvQWJ9W1I5",
      "sender" : "NbcGB1tBEGM5MfhNbDAimvpJKzvVjLQ3jW",
      "signers" : [
         {
            "account" : "0x649ca095e38a790d6c15ff78e0c6175099b428ac",
            "scopes" : "None"
         },
         {
            "account" : "0xdedbc03894301fa1f62a68460236ba978c92ef83",
            "scopes" : "None"
         }
      ],
      "size" : 412,
      "sysfee" : "997778",
      "validuntilblock" : 5277629,
      "version" : 0,
      "vmstate" : "FAULT",
      "witnesses" : [
         {
            "invocation" : "DECw8XNuyRg5vPeHxisQXlZ7VYNDxxK4xEm8zwpPyWJSSu+JaRKQxdrlPkXxXj34wc4ZSrZvKICGgPFE0ZHXhLPo",
            "verification" : "DCEC+PI2tRSlp0wGwnjRuQdWdI0tBXNS7SlzSBBHFsaKUsdBVuezJw=="
         },
         {
            "invocation" : "DEAxwi97t+rg9RsccOUzdJTJK7idbR7uUqQp0/0/ob9FbuW/tFius3/FOi82PDZtwdhk7s7KiNM/pU7vZLsgIbM0",
            "verification" : "DCEDbInkzF5llzmgljE4HSMvtrNgPaz73XO5wgVJXLHNLXRBVuezJw=="
         }
      ]
   }
}
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-16 12:13:41 +03:00
Anna Shaleva
59c98c4d09 core: always warn if accepted transaction fails verification
These warnings must be monitored by developers since it might be a sign
of behaviour difference between Go and C# nodes.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-16 12:13:40 +03:00
Roman Khimov
f4731eab91 unwrap: implement Exception type for better exception handling
Fix #3130. "Exception" is used for name since it's shorter and that's the name
used in JSON. "VMFault" was also considered as well as "FaultException"
(which mirrors result.Invoke).

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-05-15 23:00:27 +03:00
Roman Khimov
13020ccd02
Merge pull request #3431 from nspcc-dev/nativehashes-autogen
nativehashes: autogenerate native contract hashes
2024-05-15 13:36:33 +03:00
Roman Khimov
bce94dfa66
Merge pull request #3436 from nspcc-dev/fix-lint
scripts: fix linting
2024-05-14 16:16:46 +03:00
Anna Shaleva
244ca6f438 workflows: enable testing jobs for go scripts
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-14 15:55:23 +03:00
Anna Shaleva
a32217fac8 scripts: fix linting
Should be a part of #3435.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-14 15:53:08 +03:00
Roman Khimov
0435551eee
Merge pull request #3435 from nspcc-dev/extend-compare-scripts
scripts: dump diff for OnPersist and PostPersist applog
2024-05-14 15:13:03 +03:00
Anna Shaleva
0a3bf01a8f scripts: dump diff for OnPersist and PostPersist applog
Related to #3424.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-14 13:38:52 +03:00
Anna Shaleva
0aecddea10 native: autogenerate nativehashes package
Ref.
https://github.com/nspcc-dev/neo-go/pull/3402#discussion_r1577879141.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-14 09:39:53 +03:00
Roman Khimov
02ecbeb519
Merge pull request #3425 from nspcc-dev/cryptolib-test
native: add test for custom Koblitz witness verification script
2024-05-13 16:35:10 +03:00
Anna Shaleva
e275495850 *: update interop deps
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-13 10:16:04 +03:00
Anna Shaleva
6e0926e59f native: adjust NamedCurveHash values
Use 122 and 123 respectively for Secp256k1Keccak256 and
Secp256r1Keccak256, ref.
https://github.com/neo-project/neo/pull/3209#issuecomment-2095798056.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-13 10:10:56 +03:00
Anna Shaleva
988440949b native: reduce callflag scope for Koblitz verification scripts
callflag.All is too wide.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-13 09:33:42 +03:00
Roman Khimov
701ea8d5f3 native: use ABORT in Koblitz multisig
Make the script a bit shorter. ABORTMSG would cost a bit more.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-13 09:33:42 +03:00
Roman Khimov
3d1e33a502 native: make multisig koblitz easier to parse
1. Make prologue be exactly the same as regular CheckMultisig.
2. But instead of "SYSCALL System.Crypto.CheckMultisig" do INITSLOT and K check.
3. This makes all of the code from INITSLOT below be independent of N/M, so
   one can parse the script beginning in the same way CheckMultisig is parsed and
   then just compare the rest of it with some known-good blob.
4. The script becomes a tiny bit larger now, but properties above are too good.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-13 09:33:42 +03:00
Anna Shaleva
5053a073f9 rpcsrv: test calculatenetworkfee with custom Koblitz-based witness
Value calculated by calculatenetworkfee is enough to pass the real
tx verification. However, network fee may be decreased, so calculations
are not quite accurate. Need to investigate, why.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-13 09:33:42 +03:00
Anna Shaleva
71aa32406d native: add test for multisignature Koblitz witness verification
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-13 09:33:42 +03:00
Anna Shaleva
3acb132e9a native: add preferable method to TestCryptoLib_KoblitzVerificationScript
It's based on the constant-length network magic, ref.
https://github.com/nspcc-dev/neo-go/pull/3425#discussion_r1582068061.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-13 09:33:42 +03:00
Anna Shaleva
bd2f9c75e1 crypto: export GetSignedData function
It's needed for tests and further custom verification script build.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-13 09:33:42 +03:00
Anna Shaleva
34eef47a18 native: extend CryptoLib's verifyWithECDsa with hasher parameter
Replace native CryptoLib's verifyWithECDsa `curve` parameter by
`curveHash` parameter which is a enum over supported pairs of named
curves and hash functions.

Even though this change is a compatible extension of the protocol, it
changes the genesis state due to parameter renaming. But we're going to
resync chain in 3.7 release anyway, so it's not a big deal.

Also, we need to check mainnet and testnet compatibility in case if
anyone has ever called verifyWithECDsa with 24 or 25 `curve` value.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-13 09:33:41 +03:00
Anna Shaleva
7995229f6b native: add test for custom Koblitz witness verification script
Every single thing is already implemented in the protocol for Koblitz
verification scripts.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-13 09:27:42 +03:00
Roman Khimov
b21db99747
Merge pull request #3402 from nspcc-dev/native-upd
native: implement HF-based update
2024-05-10 11:53:55 +03:00
Roman Khimov
bc158eed51
Merge pull request #3428 from nspcc-dev/revert-gnark-upd
Revert "build(deps): bump github.com/consensys/gnark"
2024-05-01 16:02:43 +03:00
Anna Shaleva
ac70f069ff Revert "build(deps): bump github.com/consensys/gnark"
This reverts commit 874ed1ac2e.
We can't allow this gnark update since minimum required Go version for
NeoGo and all examples is 1.20. It will be done as a part of #3089.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-01 15:24:07 +03:00
Anna Shaleva
b54fcbcdd9
Merge pull request #3407 from nspcc-dev/copy-transaction
*: add Copy() to transaction.Transaction and payload.P2PNotaryRequest
2024-05-01 10:46:30 +03:00
Ekaterina Pavlova
8da7c0a671 notary: reuse (*Transaction).Copy where possible
Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-28 00:59:15 +05:30
Ekaterina Pavlova
956fd08adb *: add Copy() to transaction.Transaction and payload.P2PNotaryRequest
Add a method that makes a deep copy of all fields and resets size/hash
caches.

Close #3288

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-28 00:59:15 +05:30
Ekaterina Pavlova
1292a00ef9 crypto: adjust TestPublicKeys_Copy
Since the AllowedGroups []*keys.PublicKey slice is used in the
initialization, the test should use the same structures.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-28 00:12:18 +05:30
Ekaterina Pavlova
7c8d2c3ec5 crypto: add nil check for PublicKeys Copy()
Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-27 14:56:42 +05:30
Ekaterina Pavlova
df2a56908b core: move transaction Attribute value to a designated interface
Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-26 21:40:23 +05:30
Anna Shaleva
198af7f3ae
Merge pull request #3421 from nspcc-dev/dependabot/go_modules/examples/zkp/cubic_circuit/github.com/consensys/gnark-0.10.0
build(deps): bump github.com/consensys/gnark from 0.9.1 to 0.10.0 in /examples/zkp/cubic_circuit
2024-04-25 17:34:23 +03:00
dependabot[bot]
874ed1ac2e
build(deps): bump github.com/consensys/gnark
Bumps [github.com/consensys/gnark](https://github.com/consensys/gnark) from 0.9.1 to 0.10.0.
- [Release notes](https://github.com/consensys/gnark/releases)
- [Changelog](https://github.com/Consensys/gnark/blob/master/CHANGELOG.md)
- [Commits](https://github.com/consensys/gnark/compare/v0.9.1...v0.10.0)

---
updated-dependencies:
- dependency-name: github.com/consensys/gnark
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-25 13:49:06 +00:00
Roman Khimov
4a8a43b983
Merge pull request #3420 from nspcc-dev/ensure-stringers 2024-04-25 16:48:26 +03:00
Anna Shaleva
6cf785ce54 workflows: ensure autogenerated code is up-to-date
In case if source of stringers or any other autogenerated code is
updated we need to regenerate the target files. It's easy to forget
about it.

Ref. 8995f11d39cc6b5f5b0081039bbe616dd7aaf38e.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 16:36:38 +03:00
Anna Shaleva
9b8d579bce core: add unit tests for HF-based native contracts update
A part of #3213.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:26:54 +03:00
Anna Shaleva
36e128516b core: add nativenames.All list
It's useful to keep the ordered set of native contract names.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:26:54 +03:00
Anna Shaleva
4ca2686583 core: distinguish empty Hardforks map from nil
Ensure that Blockchain constructor is able to distinguish empty
Hardforks map (no hardforks should be enabled) from nil hardforks map
(the default value should be used in this case, i.e. all hardforks
should be active from genesis).

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:26:54 +03:00
Anna Shaleva
235f4398c6 native: make Oracle service handle native Oracle updates
A part of #3213.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:26:54 +03:00
Anna Shaleva
ec6fc54bc6 *: use nativehashes package where possible
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:26:54 +03:00
Anna Shaleva
2d3d52e3d0 native: add nativehashes package
Similar to nativenames, instantiate once and then reuse everywhere.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:26:54 +03:00
Anna Shaleva
82993dab2b core: extend error message for contract state check
It will give us a clue on what's wrong with contract states if something
unexpected happen.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:26:54 +03:00
Anna Shaleva
5c75ee13d0 config, native: introduce Cockatrice hard-fork
With all associated native API changes ported from
https://github.com/neo-project/neo/pull/2925 and
https://github.com/neo-project/neo/pull/3154.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:26:54 +03:00
Anna Shaleva
3a2e301267 native: make HF-specific MD cache less lazy
Initialize all necessary HF-specific contract descriptors once during
contract construction.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:26:54 +03:00
Anna Shaleva
d74dc368e0 core: unexport generic native contract methods and events
External users should use HF-specific methods and events.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:26:54 +03:00
Anna Shaleva
73c742a466 native: emit Deploy/Update notifications on native deploy/update
Ported as a part of https://github.com/neo-project/neo/pull/2942.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:26:53 +03:00
Anna Shaleva
d62fad1268 native: implement HF-based update
A part of #3213.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-25 13:16:42 +03:00
Anna Shaleva
a13dc59bd9
Merge pull request #3416 from nspcc-dev/fix-linter-cache
workflows: disable cache for golangci-lint
2024-04-22 14:33:43 +03:00
Roman Khimov
678c1982f9
Merge pull request #3414 from nspcc-dev/test-empty-script
smartcontract: ensure nil ParameterContext Item's script is marshallable
2024-04-19 16:49:52 +03:00
Roman Khimov
c84adf856a
Merge pull request #3418 from nspcc-dev/dependabot/go_modules/golang.org/x/net-0.23.0 2024-04-19 16:36:53 +03:00
dependabot[bot]
7345dbcab4
build(deps): bump golang.org/x/net from 0.22.0 to 0.23.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-19 13:19:48 +00:00
Anna Shaleva
fbe514ca91 workflows: disable cache for golangci-lint
Ref. https://github.com/golangci/golangci-lint-action/issues/135.
Otherwies we've got a set of errors on attempt to setup linter:
```
Run golangci/golangci-lint-action@v4
  with:
    version: latest
    github-token: ***
    only-new-issues: false
    skip-cache: false
    skip-pkg-cache: false
    skip-build-cache: false
    install-mode: binary
prepare environment
  Checking for go.mod: go.mod
  Received 125829120 of 781115092 (16.1%), 119.8 MBs/sec
  Received 331350016 of 781115092 (42.4%), 157.8 MBs/sec
  Received 541065216 of 781115092 (69.3%), 171.9 MBs/sec
  Received 738197504 of 781115092 (94.5%), 175.8 MBs/sec
  Cache Size: ~745 MB (781115092 B)
  /usr/bin/tar -xf /home/runner/work/_temp/6de9500e-163b-4dda-a82b-d6b2ee7b1625/cache.tzst -P -C /home/runner/work/neo-go/neo-go --use-compress-program unzstd
  Received 781115092 of 781115092 (100.0%), 148.8 MBs/sec
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/LICENSE: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/.github/workflows/test.yml: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/README.md: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/annotation_test.go: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/retention_test.go: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/main.go: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/fmt/m.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/fmt/m.proto: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_import_a1m2.pb.go: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_import_a1m1.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_import_all.proto: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_import_a1m2.proto: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_b_1/m2.pb.go: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_b_1/m1.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_b_1/m1.proto: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_b_1/m2.proto: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_import_all.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_import_a1m1.proto: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_a_1/m2.pb.go: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_a_1/m1.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_a_1/m1.proto: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_a_1/m2.proto: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_a_2/m3.proto: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_a_2/m4.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_a_2/m4.proto: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/imports/test_a_2/m3.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/extensions/ext/ext.proto: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/extensions/ext/ext.pb.go: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/extensions/extra/extra.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/extensions/extra/extra.proto: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/extensions/proto3/ext3.proto: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/extensions/proto3/ext3.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/extensions/base/base.proto: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/extensions/base/base.pb.go: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/proto2/fields.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/proto2/nested_messages.proto: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/proto2/proto2.proto: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/proto2/enum.proto: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/proto2/enum.pb.go: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/proto2/proto2.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/proto2/fields.proto: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/proto2/nested_messages.pb.go: Cannot open: File exists
  Error: /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/import_public/b.pb.go: Cannot open: File exists
  /usr/bin/tar: ../../../go/pkg/mod/google.golang.org/protobuf@v1.31.0/cmd/protoc-gen-go/testdata/import_public/a.proto: Cannot open: File exists
...
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-18 19:24:30 +03:00
Roman Khimov
83fdcc8568
Merge pull request #3412 from NeoGoBros/fix-seq-points-after-shorten-jump 2024-04-18 14:24:07 +03:00
Anna Shaleva
4b9024fa45 smartcontract: ensure nil ParameterContext Item's script is marshallable
Ensure that ParameterContext's Item with nil script can be properly
marshalled. Ref. https://github.com/neo-project/neo/pull/3198.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-18 13:55:05 +03:00
Slava0135
9b688a9ee9 compiler: reevaluate debug sequence points after shortening jumps
Signed-off-by: Slava0135 <super.novalskiy_0135@inbox.ru>
2024-04-16 10:37:06 +03:00
Roman Khimov
1786136a23
Merge pull request #3405 from nspcc-dev/dynamic-hash
cli: allow dynamic contract hash for contract bindings
2024-04-15 13:16:13 +03:00
Anna Shaleva
d3993ad54c
Merge pull request #3408 from nspcc-dev/hex-string-pub
crypto: add StringCompressed() for PublicKey
2024-04-15 12:31:18 +03:00
Anna Shaleva
db37101e34
Merge pull request #3413 from nspcc-dev/up-dbft
go.mod: import official dbft 0.2.0
2024-04-15 10:41:08 +03:00
Roman Khimov
567f9f9c6e go.mod: import official dbft 0.2.0
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-04-14 22:14:24 +03:00
Roman Khimov
fb4a4f074f
Merge pull request #3411 from nspcc-dev/improve-statediff-dumper
scripts: add contract ID/prefix parsing to state dump comparator
2024-04-11 21:23:36 +03:00
Anna Shaleva
97a19df6f0 scripts: add contract ID/prefix parsing to state dump comparator
I had this code locally for some time, let it be public.

The example output for key diff:
```
file BlockStorage_0/dump-block-0.json: block 0: key mismatch:
	Key: /////wz////4
	Contract ID: -1
	Item key (base64): DP////g=
	Item key (hex): 0cfffffff8
	Item key (bytes): [12 255 255 255 248]
vs
	Key: /////wz////5
	Contract ID: -1
	Item key (base64): DP////k=
	Item key (hex): 0cfffffff9
	Item key (bytes): [12 255 255 255 249]
```

The example output for state diff:
```
file BlockStorage_0/dump-block-0.json: block 0: state mismatch for key /////wz////4:
	Contract ID: -1
	Item key (base64): DP////g=
	Item key (hex): 0cfffffff8
	Item key (bytes): [12 255 255 255 248]
	Diff: Added vs Removed
```

The example output for value diff:
```
block 0: value mismatch for key /////wj1Y+pAvCg9TQ4FxI6jBbPyoHNA7w==:
	Contract ID: -1
	Item key (base64): CPVj6kC8KD1NDgXEjqMFs/Kgc0Dv
	Item key (hex): 08f563ea40bc283d4d0e05c48ea305b3f2a07340ef
	Item key (bytes): [8 245 99 234 64 188 40 61 77 14 5 196 142 163 5 179 242 160 115 64 239]
	Diff: QAUhAfshACgU9WPqQLwoPU0OBcSOowWz8qBzQO8o005FRjNuZW8tY29yZS12My4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQHvz5gNBCCgITmVvVG9rZW5AAEgAQAEoBk5FUC0xN0ECQBNBBSgJYmFsYW5jZU9mQAFBAigHYWNjb3VudCEBFCEBESEAIAFBBSgIZGVjaW1hbHNAACEBESEBByABQQUoD2dldEFjY291bnRTdGF0ZUABQQIoB2FjY291bnQhARQhASAhAQ4gAUEFKBBnZXRBbGxDYW5kaWRhdGVzQAAhATAhARUgAUEFKBBnZXRDYW5kaWRhdGVWb3RlQAFBAigGcHViS2V5IQEWIQERIQEcIAFBBSgNZ2V0Q2FuZGlkYXRlc0AAIQEgIQEjIAFBBSgMZ2V0Q29tbWl0dGVlQAAhASAhASogAUEFKA5nZXRHYXNQZXJCbG9ja0AAIQERIQExIAFBBSgWZ2V0TmV4dEJsb2NrVmFsaWRhdG9yc0AAIQEgIQE4IAFBBSgQZ2V0UmVnaXN0ZXJQcmljZUAAIQERIQE/IAFBBSgRcmVnaXN0ZXJDYW5kaWRhdGVAAUECKAZwdWJrZXkhARYhARAhAUYgAEEFKA5zZXRHYXNQZXJCbG9ja0ABQQIoC2dhc1BlckJsb2NrIQERIQL/ACEBTSAAQQUoEHNldFJlZ2lzdGVyUHJpY2VAAUECKA1yZWdpc3RlclByaWNlIQERIQL/ACEBVCAAQQUoBnN5bWJvbEAAIQETIQFbIAFBBSgLdG90YWxTdXBwbHlAACEBESEBYiABQQUoCHRyYW5zZmVyQARBAigEZnJvbSEBFEECKAJ0byEBFEECKAZhbW91bnQhARFBAigEZGF0YSEAIQEQIQFpIABBBSgMdW5jbGFpbWVkR2FzQAJBAigHYWNjb3VudCEBFEECKANlbmQhAREhAREhAXAgAUEFKBN1bnJlZ2lzdGVyQ2FuZGlkYXRlQAFBAigGcHVia2V5IQEWIQEQIQF3IABBBSgEdm90ZUACQQIoB2FjY291bnQhARRBAigGdm90ZVRvIQEWIQEQIQF+IABAA0ECKBVDYW5kaWRhdGVTdGF0ZUNoYW5nZWRAA0ECKAZwdWJrZXkhARZBAigKcmVnaXN0ZXJlZCEBEEECKAV2b3RlcyEBEUECKARWb3RlQARBAigHYWNjb3VudCEBFEECKARmcm9tIQEWQQIoAnRvIQEWQQIoBmFtb3VudCEBEUECKBBDb21taXR0ZWVDaGFuZ2VkQAJBAigDb2xkIQEgQQIoA25ldyEBIEABQQIAAEAAKARudWxs vs QAUhAfshACgU9WPqQLwoPU0OBcSOowWz8qBzQO8o005FRjNuZW8tY29yZS12My4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQHvz5gNBCCgITmVvVG9rZW5AAEgAQAEoBk5FUC0xN0ECQBNBBSgJYmFsYW5jZU9mQAFBAigHYWNjb3VudCEBFCEBESEAIAFBBSgIZGVjaW1hbHNAACEBESEBByABQQUoD2dldEFjY291bnRTdGF0ZUABQQIoB2FjY291bnQhARQhASAhAQ4gAUEFKBBnZXRBbGxDYW5kaWRhdGVzQAAhATAhARUgAUEFKBBnZXRDYW5kaWRhdGVWb3RlQAFBAigGcHViS2V5IQEWIQERIQEcIAFBBSgNZ2V0Q2FuZGlkYXRlc0AAIQEgIQEjIAFBBSgMZ2V0Q29tbWl0dGVlQAAhASAhASogAUEFKA5nZXRHYXNQZXJCbG9ja0AAIQERIQExIAFBBSgWZ2V0TmV4dEJsb2NrVmFsaWRhdG9yc0AAIQEgIQE4IAFBBSgQZ2V0UmVnaXN0ZXJQcmljZUAAIQERIQE/IAFBBSgRcmVnaXN0ZXJDYW5kaWRhdGVAAUECKAZwdWJrZXkhARYhARAhAUYgAEEFKA5zZXRHYXNQZXJCbG9ja0ABQQIoC2dhc1BlckJsb2NrIQERIQL/ACEBTSAAQQUoEHNldFJlZ2lzdGVyUHJpY2VAAUECKA1yZWdpc3RlclByaWNlIQERIQL/ACEBVCAAQQUoBnN5bWJvbEAAIQETIQFbIAFBBSgLdG90YWxTdXBwbHlAACEBESEBYiABQQUoCHRyYW5zZmVyQARBAigEZnJvbSEBFEECKAJ0byEBFEECKAZhbW91bnQhARFBAigEZGF0YSEAIQEQIQFpIABBBSgMdW5jbGFpbWVkR2FzQAJBAigHYWNjb3VudCEBFEECKANlbmQhAREhAREhAXAgAUEFKBN1bnJlZ2lzdGVyQ2FuZGlkYXRlQAFBAigGcHVia2V5IQEWIQEQIQF3IABBBSgEdm90ZUACQQIoB2FjY291bnQhARRBAigGdm90ZVRvIQEWIQEQIQF+IABABEECKAhUcmFuc2ZlckADQQIoBGZyb20hARRBAigCdG8hARRBAigGYW1vdW50IQERQQIoFUNhbmRpZGF0ZVN0YXRlQ2hhbmdlZEADQQIoBnB1YmtleSEBFkECKApyZWdpc3RlcmVkIQEQQQIoBXZvdGVzIQERQQIoBFZvdGVABEECKAdhY2NvdW50IQEUQQIoBGZyb20hARZBAigCdG8hARZBAigGYW1vdW50IQERQQIoEENvbW1pdHRlZUNoYW5nZWRAAkECKANvbGQhASBBAigDbmV3IQEgQAFBAgAAQAAoBG51bGw=
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-11 19:27:57 +03:00
Ekaterina Pavlova
c5dbecb754 smartcontract: support dynamic contract hash for bindings
Allow dynamic contract hash for contract bindings.

Close #3007

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-11 16:02:31 +03:00
Ekaterina Pavlova
fc79d38ad2 crypto: adjust NewPublicKeyFromString's comment
Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-11 15:24:47 +03:00
Ekaterina Pavlova
ae3515e819 crypto: add StringCompressed() for PublicKey
Add StringCompressed to get a string representation of the key in
compressed form.

Close #3263

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-11 15:24:46 +03:00
Roman Khimov
8913542f93
Merge pull request #3410 from nspcc-dev/fix-cli-desc 2024-04-10 23:21:20 +03:00
Anna Shaleva
69bcd4b7d9 cli: unify commands description
Always put blank line in the end of the command description.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-10 19:21:40 +03:00
Anna Shaleva
51537dfd29
Merge pull request #3404 from stevvns/neotest-options
neotest: add options to customize test chain
2024-04-10 10:17:40 +03:00
Anna Shaleva
ee1ee56f97
Merge pull request #3409 from nspcc-dev/update-codecov
workflows: update CodeCov action, use token for upload
2024-04-09 14:56:34 +03:00
Roman Khimov
8c1d061446 workflows: update CodeCov action, use token for upload
It fails now without a token.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-04-09 13:39:11 +03:00
Anna Shaleva
a28e5b24b2
Merge pull request #3406 from nspcc-dev/error-message
native: adjust error message for ExecFeeFactor and StoragePrice
2024-04-09 10:59:03 +03:00
stevvns
7aa5983543 neotest: add options to customize test chain
Close #3403

Signed-off-by: stevvns <stevvns@yandex.com>
2024-04-09 09:18:36 +04:00
Ekaterina Pavlova
fcbfc3b807 native: adjust error message for ExecFeeFactor and StoragePrice
Close #3311

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-09 01:51:03 +03:00
Roman Khimov
cf49e8c4c8
Merge pull request #3401 from fyfyrchik/compiler-named-return-defaults
compiler: Initialize named returns to default values
2024-04-05 15:25:11 +03:00
Evgenii Stratonikov
78cefca5c9 compiler: Initialize named returns to default values
Make them behave as locals. We must initialize them at the start
because the default value could also be used inside the function body.

Signed-off-by: Evgenii Stratonikov <fyfyrchik@runbox.com>
2024-04-04 18:00:26 +03:00
Anna Shaleva
f2bb4d455b
Merge pull request #3389 from nspcc-dev/import-wallet-error
cli: improve wallet read related errors
2024-04-04 14:10:47 +03:00
Roman Khimov
f553f77d20
Merge pull request #3400 from nspcc-dev/fix-TestServerStartAndShutdown
network: take care of TestServerStartAndShutdown
2024-04-04 13:56:22 +03:00
Ekaterina Pavlova
700a550973 cli: improve wallet unmarshalling error
Made errors more user-friendly.
```
./bin/neo-go wallet import --wif qweqweqweqwe -w wallet1.json
failed to read wallet: open wallet: open wallet.json: no such file or
directory

touch wallet.json

./bin/neo-go wallet import --wif qweqweqweqwe -w wallet.json
failed to read wallet: unmarshal wallet: EOF
```

Close #3134

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-04 13:46:54 +03:00
Anna Shaleva
f84f072a29 network: take care of TestServerStartAndShutdown
We don't have a reliable way to know when transports are started since
their start is being performed in a separate goroutine:

927dbb6dc4/pkg/network/server.go (L297-L299)

And transports start is not connected with main server routine, thus,
just wait for some time for the transports goroutine to be started.

Also wait for the peer to be properly registered.

Close #3399.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-04 13:29:47 +03:00
Roman Khimov
927dbb6dc4
Merge pull request #3398 from nspcc-dev/enforce-testws-close 2024-04-04 13:12:38 +03:00
Anna Shaleva
e5c919f701 rpcsrv: enforce WS connection close on test cleanup
Do not wait until wsReader routine gracefully finishes its work before
WS connection close. Instead, firstly close the connection, and after
that wait for proper wsReader exit.

It's a harsh way, but I don't have any other options to try, because
wsReader routine hangs on `ws.ReadMessage()` operation for more than
ReadDeadline (more than 5 seconds) during test cleanup which results in
the test timeout.

Close #3378.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-04 12:03:06 +03:00
Roman Khimov
22af33a14e
Merge pull request #3397 from nspcc-dev/fix-TestWSClient_SubscriptionsCompat 2024-04-04 12:02:20 +03:00
Anna Shaleva
ef3ec190d0 rpcsrv: allow one-block slippage in TestWSClient_SubscriptionsCompat
Close #2956. The failure reason is similar to the one described in #3396
for TestNotary: Blockchain's notificationDispatcher is listening to
block events from storeBlock via separate channel. By the moment single
block addition is finished, notification may or may not be properly
handled by notificationDispatcher, especially given the fact that our
runners are slow. As a result, assert.Eventually with 1-second awaiting
period may fail. This issue is solved by adding one more block, because
the second AddBlock finishes only when it sends block addition event to
notificationDispatcher loop, which means that the previous event was
handled.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-04 11:02:15 +03:00
Anna Shaleva
b1a986fba8
Merge pull request #3386 from nspcc-dev/getversion
rpcsrv: add SessionEnabled, MaxIteratorResultItems to `getversion`
2024-04-04 10:38:09 +03:00
Roman Khimov
f6901806a8
Merge pull request #3396 from nspcc-dev/fix-TestNotary
services: allow some slippage in TestNotary
2024-04-03 23:26:00 +03:00
Ekaterina Pavlova
686c77aeea rpcsrv: add SessionEnabled, MaxIteratorResultItems to getversion
Extend getversion RPC response with RPC server settings (SessionEnabled,
MaxIteratorResultItems).Port neo-project/neo-modules#878.

Close #3276

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-03 22:42:14 +03:00
Anna Shaleva
89ef26164c
Merge pull request #3384 from nspcc-dev/TestWSClientsLimit
rpcsrv: fix TestWSClientsLimit
2024-04-03 20:01:18 +03:00
Anna Shaleva
4c288720cd services: allow some slippage in TestNotary
1. Allow 1-block slippage for multisignature request block generation to
   ensure that PostPersist for fb's NVB-th block is properly finished.
2. Allow 1-block slippage before sent request checks to ensure that
   PostPersist for NVB fb's NVB-th block was finished and all
   stale mains were properly marked by Notary service.

Overall, this commits ports the approach of #3390 to the whole test.

Close #3366.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-03 18:44:23 +03:00
Ekaterina Pavlova
f8c2d269fe rpcsrv: increase timeout in TestWSClientsLimit
Still not fast enough for connections to be alive for the default case
of 64+1 connections. Some of them are start to die after 5 seconds of
test:
```
2024-04-03T14:06:22.5504034Z === RUN   TestWSClientsLimit
2024-04-03T14:06:22.5504142Z === RUN   TestWSClientsLimit/default
2024-04-03T14:06:22.5504868Z     logger.go:146: 2024-04-03T14:04:30.637Z
	INFO	initial gas supply is not set or wrong, setting default
	value	{"InitialGASSupply": "52000000"}
2024-04-03T14:06:22.5505730Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	P2PNotaryRequestPayloadPool size is not set or wrong,
setting default value	{"P2PNotaryRequestPayloadPoolSize": 1000}
2024-04-03T14:06:22.5506373Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	MaxBlockSize is not set or wrong, setting default
value	{"MaxBlockSize": 262144}
2024-04-03T14:06:22.5507094Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	MaxBlockSystemFee is not set or wrong, setting default
 value	{"MaxBlockSystemFee": 900000000000}
2024-04-03T14:06:22.5507843Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	MaxTransactionsPerBlock is not set or wrong, using
default value	{"MaxTransactionsPerBlock": 512}
2024-04-03T14:06:22.5508644Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	MaxValidUntilBlockIncrement is not set or wrong, using
 default value	{"MaxValidUntilBlockIncrement": 5760}
2024-04-03T14:06:22.5509114Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	no storage version found! creating genesis block
2024-04-03T14:06:22.5509788Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	ExtensiblePoolSize is not set or wrong, using default
value	{"ExtensiblePoolSize": 20}
2024-04-03T14:06:22.5510476Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	SessionPoolSize is not set or wrong, setting default
value	{"SessionPoolSize": 20}
2024-04-03T14:06:22.5511258Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	MaxIteratorResultItems is not set or wrong, setting
default value	{"MaxIteratorResultItems": 100}
2024-04-03T14:06:22.5511951Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	MaxFindResultItems is not set or wrong, setting
default value	{"MaxFindResultItems": 100}
2024-04-03T14:06:22.5512598Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	MaxNEP11Tokens is not set or wrong, setting default
value	{"MaxNEP11Tokens": 100}
2024-04-03T14:06:22.5513316Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	MaxRequestBodyBytes is not set or wong, setting
default value	{"MaxRequestBodyBytes": 5242880}
2024-04-03T14:06:22.5514060Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	MaxRequestHeaderBytes is not set or wong, setting
default value	{"MaxRequestHeaderBytes": 1048576}
2024-04-03T14:06:22.5514755Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	MaxWebSocketClients is not set or wrong, setting
default value	{"MaxWebSocketClients": 64}
2024-04-03T14:06:22.5515215Z     logger.go:146: 2024-04-03T14:04:30
.637Z	INFO	starting rpc-server	{"endpoint": "127.0.0.1:0"}
2024-04-03T14:06:22.5515874Z     logger.go:146: 2024-04-03T14:04:31
.200Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5516442Z     logger.go:146: 2024-04-03T14:04:31
.200Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5516973Z     logger.go:146: 2024-04-03T14:04:31
.226Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5517502Z     logger.go:146: 2024-04-03T14:04:31
.388Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5518027Z     logger.go:146: 2024-04-03T14:04:31
.398Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5518551Z     logger.go:146: 2024-04-03T14:04:31
.420Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5519082Z     logger.go:146: 2024-04-03T14:04:31
.577Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5519606Z     logger.go:146: 2024-04-03T14:04:31
.587Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5520133Z     logger.go:146: 2024-04-03T14:04:31
.624Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5520850Z     logger.go:146: 2024-04-03T14:04:31
.780Z	INFO	persisted to disk	{"blocks": 0, "keys": 127,
"headerHeight": 0, "blockHeight": 0, "took": "121.8µs"}
2024-04-03T14:06:22.5521398Z     logger.go:146: 2024-04-03T14:04:31
.780Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5521925Z     logger.go:146: 2024-04-03T14:04:31
.812Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5522452Z     logger.go:146: 2024-04-03T14:04:31
.969Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5522975Z     logger.go:146: 2024-04-03T14:04:32
.016Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5523507Z     logger.go:146: 2024-04-03T14:04:32
.172Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5524033Z     logger.go:146: 2024-04-03T14:04:32
.219Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5524555Z     logger.go:146: 2024-04-03T14:04:32
.273Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5525081Z     logger.go:146: 2024-04-03T14:04:32
.376Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5525604Z     logger.go:146: 2024-04-03T14:04:32
.423Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5526131Z     logger.go:146: 2024-04-03T14:04:32
.563Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5526691Z     logger.go:146: 2024-04-03T14:04:32
.627Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5527254Z     logger.go:146: 2024-04-03T14:04:32
.767Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5527777Z     logger.go:146: 2024-04-03T14:04:32
.830Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5528304Z     logger.go:146: 2024-04-03T14:04:32
.955Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5528824Z     logger.go:146: 2024-04-03T14:04:33
.033Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5529352Z     logger.go:146: 2024-04-03T14:04:33
.158Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5529871Z     logger.go:146: 2024-04-03T14:04:33
.237Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5530395Z     logger.go:146: 2024-04-03T14:04:33
.322Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5530921Z     logger.go:146: 2024-04-03T14:04:33
.348Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5531472Z     logger.go:146: 2024-04-03T14:04:33
.444Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5532031Z     logger.go:146: 2024-04-03T14:04:33
.535Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5532555Z     logger.go:146: 2024-04-03T14:04:33
.645Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5533084Z     logger.go:146: 2024-04-03T14:04:33
.724Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5533604Z     logger.go:146: 2024-04-03T14:04:33
.848Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5534132Z     logger.go:146: 2024-04-03T14:04:33
.926Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5534662Z     logger.go:146: 2024-04-03T14:04:34
.036Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5535190Z     logger.go:146: 2024-04-03T14:04:34
.130Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5535712Z     logger.go:146: 2024-04-03T14:04:34
.224Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5536231Z     logger.go:146: 2024-04-03T14:04:34
.318Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5536758Z     logger.go:146: 2024-04-03T14:04:34
.413Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5537277Z     logger.go:146: 2024-04-03T14:04:34
.423Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5537805Z     logger.go:146: 2024-04-03T14:04:34
.423Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5538329Z     logger.go:146: 2024-04-03T14:04:34
.523Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5538855Z     logger.go:146: 2024-04-03T14:04:34
.602Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5539382Z     logger.go:146: 2024-04-03T14:04:34
.612Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5539908Z     logger.go:146: 2024-04-03T14:04:34
.712Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5540431Z     logger.go:146: 2024-04-03T14:04:34
.805Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5540956Z     logger.go:146: 2024-04-03T14:04:34
.915Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5541515Z     logger.go:146: 2024-04-03T14:04:34
.993Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5542070Z     logger.go:146: 2024-04-03T14:04:35
.118Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5542599Z     logger.go:146: 2024-04-03T14:04:35
.181Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5543125Z     logger.go:146: 2024-04-03T14:04:35
.307Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5543650Z     logger.go:146: 2024-04-03T14:04:35
.385Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5544169Z     logger.go:146: 2024-04-03T14:04:35
.426Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5544695Z     logger.go:146: 2024-04-03T14:04:35
.510Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5545262Z     logger.go:146: 2024-04-03T14:04:35
.589Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5545839Z     logger.go:146: 2024-04-03T14:04:35
.698Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5546421Z     logger.go:146: 2024-04-03T14:04:35
.777Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5547045Z     logger.go:146: 2024-04-03T14:04:35
.902Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5547593Z     logger.go:146: 2024-04-03T14:04:35
.980Z	DEBUG	processing rpc request	{"method": "getversion",
"params": "[]"}
2024-04-03T14:06:22.5551421Z     subscription_test.go:620:
2024-04-03T14:06:22.5551977Z         	Error Trace:
D:/a/neo-go/neo-go/pkg/services/rpcsrv/subscription_test.go:620
2024-04-03T14:06:22.5552611Z
C:/hostedtoolcache/windows/go/1.22.1/x64/src/runtime/asm_amd64.s:1695
2024-04-03T14:06:22.5552821Z         	Error:      	Received
unexpected error:
2024-04-03T14:06:22.5553328Z         	            	read tcp 127.0
.0.1:51969->127.0.0.1:51909: i/o timeout
2024-04-03T14:06:22.5553535Z         	Test:
TestWSClientsLimit/default
2024-04-03T14:06:22.5553676Z     subscription_test.go:620:
2024-04-03T14:06:22.5554223Z         	Error Trace:
D:/a/neo-go/neo-go/pkg/services/rpcsrv/subscription_test.go:620
2024-04-03T14:06:22.5554831Z
C:/hostedtoolcache/windows/go/1.22.1/x64/src/runtime/asm_amd64.s:1695
2024-04-03T14:06:22.5555036Z         	Error:      	Received
unexpected error:
2024-04-03T14:06:22.5555521Z         	            	read tcp 127.0
.0.1:51970->127.0.0.1:51909: i/o timeout
2024-04-03T14:06:22.5555723Z         	Test:
TestWSClientsLimit/default
2024-04-03T14:06:22.5555860Z     subscription_test.go:620:
2024-04-03T14:06:22.5556336Z         	Error Trace:
D:/a/neo-go/neo-go/pkg/services/rpcsrv/subscription_test.go:620
2024-04-03T14:06:22.5556953Z
C:/hostedtoolcache/windows/go/1.22.1/x64/src/runtime/asm_amd64.s:1695
2024-04-03T14:06:22.5557160Z         	Error:      	Received
unexpected error:
2024-04-03T14:06:22.5557636Z         	            	read tcp 127.0
.0.1:51973->127.0.0.1:51909: i/o timeout
2024-04-03T14:06:22.5557831Z         	Test:
TestWSClientsLimit/default
2024-04-03T14:06:22.5557967Z     subscription_test.go:620:
2024-04-03T14:06:22.5558437Z         	Error Trace:
D:/a/neo-go/neo-go/pkg/services/rpcsrv/subscription_test.go:620
2024-04-03T14:06:22.5559028Z
C:/hostedtoolcache/windows/go/1.22.1/x64/src/runtime/asm_amd64.s:1695
2024-04-03T14:06:22.5559229Z         	Error:      	Received
unexpected error:
2024-04-03T14:06:22.5559696Z         	            	read tcp 127.0
.0.1:51971->127.0.0.1:51909: i/o timeout
2024-04-03T14:06:22.5559891Z         	Test:
TestWSClientsLimit/default
2024-04-03T14:06:22.5560024Z     subscription_test.go:620:
2024-04-03T14:06:22.5560490Z         	Error Trace:
D:/a/neo-go/neo-go/pkg/services/rpcsrv/subscription_test.go:620
2024-04-03T14:06:22.5561142Z
C:/hostedtoolcache/windows/go/1.22.1/x64/src/runtime/asm_amd64.s:1695
2024-04-03T14:06:22.5561371Z         	Error:      	Received
unexpected error:
2024-04-03T14:06:22.5561849Z         	            	read tcp 127.0
.0.1:51972->127.0.0.1:51909: i/o timeout
2024-04-03T14:06:22.5562043Z         	Test:
TestWSClientsLimit/default
2024-04-03T14:06:22.5562179Z     subscription_test.go:630:
2024-04-03T14:06:22.5562638Z         	Error Trace:
D:/a/neo-go/neo-go/pkg/services/rpcsrv/subscription_test.go:630
2024-04-03T14:06:22.5562879Z         	Error:      	An error is
expected but got nil.
2024-04-03T14:06:22.5563073Z         	Test:
TestWSClientsLimit/default
2024-04-03T14:06:22.5563361Z         	Messages:   	The connection
 beyond the limit should fail
2024-04-03T14:06:22.5563886Z     logger.go:146: 2024-04-03T14:04:36
.481Z	INFO	shutting down RPC server	{"endpoint": "127.0.0
.1:51908"}
```

Close #3379

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-03 18:03:55 +03:00
Ekaterina Pavlova
698bdc7eea rpcsrv: fix TestWSClientsLimit
Made connections in parallel to check the limit and attempt to make one
more connection beyond the limit. Only "default" test case is failing,
because default number of connections is 64 (quite large for slow
runners). The failure reason is:
* given ~1 second for [dealing + request] per connection (time is taken
from the test log)
* by the moment 65-th connection is reached, some connections from the
start of the test have died due to inactivity (this process literally
takes 1 minute)

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-03 18:03:55 +03:00
Roman Khimov
0280ceefe6
Merge pull request #3395 from nspcc-dev/fix-awaitabletxtest
cli: ensure all outcomes are handled in TestAwaitUtilCancelTx
2024-04-03 17:55:35 +03:00
Anna Shaleva
b6a9c64c55 cli: ensure all outcomes are handled in TestAwaitUtilCancelTx
Close #3365.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-03 16:40:11 +03:00
Roman Khimov
be1b97d04e
Merge pull request #3392 from nspcc-dev/adjust-deadlines
*: adjust WS connection RW deadlines
2024-04-03 14:50:14 +03:00
Anna Shaleva
29deba45ca services: refactor test WS reader
1. Replace isFinished atomic variable with a channel, no functional changes
   here, just use more common way as all our services do.

2. Do not check erors from SetReadDeadline and ReadMessage on exit. It
   seems to be not quite right because connection is not closed by this
   moment, and thus, these error checks are racy.
3. Add read timeout for the message reader. It is needed because some
   tests may leave message unread in the end which results in hanging
   test cleanup.
4. Add drain loop to message reader in order not to block WS reader on
   sending message.

Ref. https://github.com/nspcc-dev/neo-go/pull/3392#issuecomment-2031590403.
It's clear that TestBadSubUnsub is hanging on test cleanup, in
particular, on attempt to wait for wsRead routine to exit. The only
place where wsRead routine may hang is sending to msgCh in case if
receiver is not going to read from this channel:
```
2024-04-02T08:14:51.4957621Z goroutine 14329 [chan receive]:
2024-04-02T08:14:51.4958010Z github.com/nspcc-dev/neo-go/pkg/services/rpcsrv.initCleanServerAndWSClient.func1()
2024-04-02T08:14:51.4958344Z 	D:/a/neo-go/neo-go/pkg/services/rpcsrv/subscription_test.go:80 +0x71
2024-04-02T08:14:51.4958457Z testing.(*common).Cleanup.func1()
2024-04-02T08:14:51.4958757Z 	C:/hostedtoolcache/windows/go/1.22.1/x64/src/testing/testing.go:1175 +0x17a
2024-04-02T08:14:51.4958903Z testing.(*common).runCleanup(0xc002cf5860, 0x0)
2024-04-02T08:14:51.4959193Z 	C:/hostedtoolcache/windows/go/1.22.1/x64/src/testing/testing.go:1353 +0x262
2024-04-02T08:14:51.4959291Z testing.tRunner.func2()
2024-04-02T08:14:51.4959566Z 	C:/hostedtoolcache/windows/go/1.22.1/x64/src/testing/testing.go:1683 +0x51
2024-04-02T08:14:51.4959695Z testing.tRunner(0xc002cf5860, 0x141687410)
2024-04-02T08:14:51.4959976Z 	C:/hostedtoolcache/windows/go/1.22.1/x64/src/testing/testing.go:1695 +0x25e
2024-04-02T08:14:51.4960115Z created by testing.(*T).Run in goroutine 1
2024-04-02T08:14:51.4960385Z 	C:/hostedtoolcache/windows/go/1.22.1/x64/src/testing/testing.go:1742 +0x826
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-03 12:56:07 +03:00
Anna Shaleva
c81ed22698
Merge pull request #3394 from nspcc-dev/better-notary-actor
rpcclient: make default Notary actor options customizable
2024-04-03 11:02:24 +03:00
Anna Shaleva
c5ba53986f
Merge pull request #3385 from nspcc-dev/findstorage
rpcsrv: fix findstorage if a contract state is not found
2024-04-03 11:00:55 +03:00
Ekaterina Pavlova
fff25bd85c rpcsrv: fix findstorage if a contract state is not found
Previously findstorage returns null for the results key if a contract
state is not found. C# returns an empty list.

Close #3370

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-02 19:56:44 +03:00
Anna Shaleva
182762af5a rpcclient: make default Notary actor options customizable
This commit allows to override only MainModifier omitting overriding
MainCheckerModifier.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-02 18:56:43 +03:00
Roman Khimov
e7a0ded65e
Merge pull request #3391 from nspcc-dev/fix-tx-awaiting
cli: unify `canceltx` command output
2024-04-02 15:28:01 +03:00
Roman Khimov
7202518fcf
Merge pull request #3390 from nspcc-dev/fix-notary-test
services: fix race in TestNotary
2024-04-02 15:26:31 +03:00
Anna Shaleva
e0e7fdf810 cli: unify canceltx command output
Always return "Target transaction accepted" error if the target transation was
either accepted by the moment of command run or during the command
handling. Exit with code 1 in both cases. Adjust TestAwaitUtilCancelTx
correspondingly, allow both cases in test. Simplify the test along the
way, remove useless code.

Close #3365.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-02 15:23:25 +03:00
Anna Shaleva
f95004ad83 services: fix race in TestNotary
Close #3366. Roll back the test structure to the one that it has before
d2a7162217. Add one extra block to ensure
that main transaction won't be finilized. Add NVB increment slippage to
avoid race between the first fallback acceptance and block acceptance.
Add NVB increment slippage to the rest of fallbacks for test structure
unification.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-02 15:15:02 +03:00
Anna Shaleva
309016561d
Merge pull request #3393 from nspcc-dev/testrpc
rpc: fix TestRPC timeout
2024-04-02 12:37:16 +03:00
Ekaterina Pavlova
65dbd537ec rpc: fix TestRPC timeout
Increase timeout to prevent `context deadline exceeded (Client.Timeout
exceeded while awaiting headers)`.

Close #2975

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-02 11:11:14 +03:00
Anna Shaleva
b947d09552 *: adjust WS connection RW deadlines
Yet another attempt to close #3378.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-02 10:31:38 +03:00
Roman Khimov
5c995e71b5
Merge pull request #3387 from nspcc-dev/fix-test-wsreader 2024-04-01 19:22:55 +03:00
Anna Shaleva
5b30d15f8e rpcsrv: properly cleanup network server in tests
Port the idea of https://github.com/nspcc-dev/neo-go/pull/3380.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-01 18:54:35 +03:00
Anna Shaleva
57d82c1281 rpcsrv: properly cleanup WS reader in tests
Close #3378.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-01 18:54:35 +03:00
Roman Khimov
e341e64684
Merge pull request #3388 from nspcc-dev/wrkfl-upd
workflows: update CodeQL version
2024-04-01 18:46:59 +03:00
Anna Shaleva
cd215fe096
Merge pull request #3382 from xiaoxianBoy/fix-typos
chore: fix typos
2024-04-01 18:41:01 +03:00
Anna Shaleva
d7ab7634ef workflows: update CodeQL version
Warning: CodeQL Action v2 will be deprecated on December 5th, 2024. Please update all occurrences of the CodeQL Action in your workflow files to v3. For more information, see https://github.blog/changelog/2024-01-12-code-scanning-deprecation-of-codeql-action-v2/

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-04-01 18:27:59 +03:00
Anna Shaleva
00ac38b545
Merge pull request #3377 from nspcc-dev/test-subclient
rpcsrv: fix TestSubClientWaitWithMissedEvent
2024-04-01 11:13:23 +03:00
Ekaterina Pavlova
56e6119f78 rpcsrv: fix TestSubClientWaitWithMissedEvent
Add error channel to prevent data race in the test.
Increase waiting interval for subscriptions awaiting up to 2 seconds.
Failing is caused by slow subscriptions.

Close #2958

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-04-01 10:52:13 +03:00
snoppy
d3c8916827
chore: fix typos 2024-04-01 09:43:20 +08:00
Anna Shaleva
86f16bb931
Merge pull request #3375 from nspcc-dev/standby-note
docs: adjust StandByCommittee node config documentation
2024-03-27 21:32:34 +03:00
Anna Shaleva
e27a822d4b
Merge pull request #3376 from nspcc-dev/test-nep17-transfer
cli: fix TestNEP17Transfer fail
2024-03-27 20:55:27 +03:00
Anna Shaleva
687a724d2c docs: adjust StandByCommittee node config documentation
Add a note about elements order.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-27 20:52:18 +03:00
Ekaterina Pavlova
8d0d5cb7cd cli: fix TestNEP17Transfer fail
To prevent `Expired transaction (-510) - transaction has expired:
ValidUntilBlock = 8, current height = 8` VUB have been increased.

Close #3343

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-27 11:16:43 +03:00
Anna Shaleva
627a0abb57
Merge pull request #3371 from nspcc-dev/upd-dbft
consensus: integrate dBFT pre-0.2.0
2024-03-25 19:54:05 +03:00
Anna Shaleva
beee2605a3 consensus: use better dbFT
Fetch fresh dbft version with minor adjustments.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-25 19:21:51 +03:00
Anna Shaleva
708b439f4a consensus: remove unused dBFT payload methods
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-25 19:21:51 +03:00
Anna Shaleva
3e6dfff503 consensus: fetch dbft pre-0.2.0 version
Try out updated dBFT interface.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-25 19:21:50 +03:00
Roman Khimov
f8ca51db93
Merge pull request #3374 from nspcc-dev/improve-err
*: improve error text for System.Crypto.CheckMultisig handling
2024-03-25 19:20:35 +03:00
Anna Shaleva
85a2a9a989 *: improve error text for System.Crypto.CheckMultisig handling
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-25 19:16:21 +03:00
Anna Shaleva
37d7a3a2d5
Merge pull request #3301 from nspcc-dev/keccak256
interop: add keccak256 implementation
2024-03-23 14:23:10 +03:00
Ekaterina Pavlova
c090628ea5 rpcsrv: update block20StateRootLE
Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-22 17:20:06 +03:00
Ekaterina Pavlova
6d1a22dcb3 *: update interop deps
Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-22 17:17:30 +03:00
Ekaterina Pavlova
1840c057bd interop: add keccak256 implementation
Port neo-project/neo#2925.

Close #3295

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-22 17:15:43 +03:00
Anna Shaleva
fa1c07e7e6
Merge pull request #3362 from nspcc-dev/getCommitteeAddress
native: add getCommitteeAddress method
2024-03-22 17:13:29 +03:00
Anna Shaleva
d5a5e4c125
Merge pull request #3368 from nspcc-dev/test-dial
rpcsrv: fix TestRPC failing
2024-03-22 16:53:09 +03:00
Ekaterina Pavlova
f8ebed2da4 *: update interop deps
Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-22 16:48:58 +03:00
Ekaterina Pavlova
72484a33eb rpcsrv: update block20StateRootLE
Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-22 16:46:59 +03:00
Ekaterina Pavlova
e0328cc1f8 native: add getCommitteeAddress method
Port neo-project/neo#3154.

Close #3334

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-22 16:46:59 +03:00
Anna Shaleva
900ef462df
Merge pull request #3369 from nspcc-dev/test-await
cli: fix TestAwaitUtilCancelTx failing
2024-03-22 16:33:25 +03:00
Ekaterina Pavlova
d80e14dcbb cli: fix TestAwaitUtilCancelTx failing
Occasionally the block is being accepted right after main transaction
submission. Added two branches into this TestAwaitUtilCancelTx. One
branch handles the case of original transaction acceptance, the
other branch handles the conflicting transaction acceptance.

Close #3365

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-22 16:22:11 +03:00
Ekaterina Pavlova
f409fc36e2 rpcsrv: fix TestRPC failing
Default http.Client and http.Transport can be really slow. Also on
windows Timeout: time.Second was not enough. Probably network related
issue. As mentioned in https://github
.com/nspcc-dev/neo-go/issues/2975#issuecomment-1750523651 forcely use
only tcp4 and FallbackDelay: -1. This made TestRPC little bit faster so
gh windows runner can manage it without timeout or POST request fails.

Close #2975
Close #3314

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-22 16:18:19 +03:00
Anna Shaleva
b028c772f2
Merge pull request #3364 from nspcc-dev/fuzz
network: fix logging data race in the package
2024-03-21 19:52:33 +03:00
Anna Shaleva
308475f746
Merge pull request #3351 from nspcc-dev/CommitteeChanged
native: add committee change events
2024-03-21 19:37:43 +03:00
Ekaterina Pavlova
31548dc28f network: fix logging data race in the package
Nested goroutines could cause logging race.

Close #3316

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-20 13:12:14 +03:00
Ekaterina Pavlova
7c2575568d rpcsrv: update block20StateRootLE
Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-19 23:00:06 +03:00
Ekaterina Pavlova
270515de6a native: add committee change events
Port neo-project/neo#3158.

Close #3326

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-19 23:00:06 +03:00
Roman Khimov
a81dc5c795
Merge pull request #3356 from fyfyrchik/fix-checkresok
rpcclient: return FaultException in checkResOk if any
2024-03-19 22:32:45 +03:00
Roman Khimov
da4e80e7a0
Merge pull request #3357 from nspcc-dev/fix-notary
core: prohibit reentry to Notary withdraw
2024-03-19 22:31:49 +03:00
Evgenii Stratonikov
1a3a494459 rpcclient: return FaultException in checkResOk if any
FaultException can be non-empty even in Halt state when there were
problems with stack marshaling to JSON.

Signed-off-by: Evgenii Stratonikov <fyfyrchik@runbox.com>
2024-03-19 18:39:02 +03:00
Roman Khimov
7e12cc11e4
Merge pull request #3361 from nspcc-dev/fix-rpc-511
rpcsrv: fix insufficient funds use
2024-03-18 20:49:10 +03:00
Roman Khimov
27f79b8c63 rpcsrv: fix insufficient funds use
This is not the way intended in https://github.com/neo-project/proposals/pull/156.
-511 covers _both_ cases because users hardly can distinguish one from another,
it's just that our mempool implementation has error codes for both..

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-03-18 20:37:39 +03:00
Roman Khimov
445ab97906
Merge pull request #3360 from nspcc-dev/adj-mempool-err-codes
rpcsrv: fix RPC error codes proposal compatibility
2024-03-18 18:55:42 +03:00
Anna Shaleva
82e52c4f6d rpcsrv: fix RPC error codes proposal compatibility
mempool.ErrInsufficientFunds is used when sender doesn't have enough
balance to pay the submitted transaction fees (-511 code according to
https://github.com/neo-project/proposals/pull/156). mempool.ErrConflict is
used when sender is not able to pay the overall transactions fee sum in
the pool (generic -500 error according to the proposal).

This bugfix is kind of breaking change for those users who relied on the
old -511 code previously returning "insufficient funds" error.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-18 18:05:19 +03:00
Anna Shaleva
335550fb1e rpcsrv: generate randome nonce for RPC server test transactions
Avoid mempool conflicts in tests.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-18 18:03:58 +03:00
Anna Shaleva
a6f52a7180 core: prohibit reentry to Notary withdraw
If we're withdrawing funds to contract that has onNEP17Payment method,
then it may call Notary's withdraw one more time, but the account's
state is not yet updated by this moment.

The problem is similar to https://github.com/neo-project/neo/pull/2734.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-18 17:08:32 +03:00
Anna Shaleva
bfc3aa6b67
Merge pull request #3349 from nspcc-dev/LastGasPerVote
native: clear LastGasPerVote when voting for NULL
2024-03-15 12:06:48 +03:00
Ekaterina Pavlova
0e6fbadfd5 native: clear LastGasPerVote when voting for NULL
Port neo-project/neo#3173.

Close #3345

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-15 10:51:32 +03:00
Roman Khimov
9c83beffbb
Merge pull request #3355 from nspcc-dev/close-rpc-clietn
rpcsrv: properly close RPC clients in tests
2024-03-14 11:56:04 +03:00
Anna Shaleva
37d4012306 rpcsrv: properly close RPC clients in tests
This commit doesn't fix anything, but clients should be closed, it's
just a good practice.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-14 11:04:39 +03:00
Anna Shaleva
67d39177d8
Merge pull request #3350 from nspcc-dev/tune-rpc-tests
rpcsrv: close idle client connections in doRPCCallOverHTTP
2024-03-14 10:52:35 +03:00
Roman Khimov
1679b162b8
Merge pull request #3354 from nspcc-dev/dependabot/go_modules/google.golang.org/protobuf-1.33.0
build(deps): bump google.golang.org/protobuf from 1.32.0 to 1.33.0
2024-03-14 08:29:11 +03:00
Roman Khimov
45c6a7dcd7
Merge pull request #3352 from nspcc-dev/dependabot/go_modules/examples/zkp/cubic_circuit/google.golang.org/protobuf-1.33.0
build(deps): bump google.golang.org/protobuf from 1.31.0 to 1.33.0 in /examples/zkp/cubic_circuit
2024-03-14 08:28:56 +03:00
Roman Khimov
077b4f9097
Merge pull request #3353 from nspcc-dev/dependabot/go_modules/examples/nft-nd-nns/google.golang.org/protobuf-1.33.0 2024-03-14 08:28:34 +03:00
dependabot[bot]
b015c7b05d
build(deps): bump google.golang.org/protobuf from 1.32.0 to 1.33.0
Bumps google.golang.org/protobuf from 1.32.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-13 23:40:17 +00:00
dependabot[bot]
57d828c4ab
build(deps): bump google.golang.org/protobuf in /examples/nft-nd-nns
Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-13 23:07:18 +00:00
dependabot[bot]
b78b715259
build(deps): bump google.golang.org/protobuf
Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-13 23:06:06 +00:00
Roman Khimov
86faf7b343 rpcsrv: close idle client connections in doRPCCallOverHTTP
Shouldn't affect things much, yet at the same time we no longer need any
connection after we're done with the request.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-03-13 12:58:15 +03:00
Anna Shaleva
319880e201
Merge pull request #3340 from nspcc-dev/wsclient-test
rpcclient: fix TestWSClientNonBlockingEvents
2024-03-13 12:08:11 +03:00
Ekaterina Pavlova
0016b6b630 rpc: add synchronisation for httptest.Server in tests
Add waiting for startSending to ensure that the client is ready before
the server starts sending messages.

Close #3005
Close #3312

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-13 11:41:43 +03:00
Anna Shaleva
b12ef701f0
Merge pull request #3344 from nspcc-dev/concurrent-test
rpcsrv: fix concurrent test TestClient_IteratorSessions
2024-03-12 00:04:31 +03:00
Ekaterina Pavlova
588d7c6418 rpcsrv: fix concurrent test TestClient_IteratorSessions
The default for `MaxConnsPerHost` is "no limit", so it'll use as many
connections as it can (potentially hitting MacOS/Windows limits
https://github.com/golang/go/issues/20960#issuecomment-447918270 ).

Close #3300

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-11 22:00:23 +03:00
Anna Shaleva
0e47d662b5
Merge pull request #3347 from nspcc-dev/inc-test-timeout
workflows: give tests more time
2024-03-11 10:38:15 +03:00
Roman Khimov
54c53cf6ca workflows: give tests more time
We have more and more timeouts happening for test runs, so 10m is not enough
for busy GH machines sometime. I think we can just give them a bit more time.

Refs. #2379 though.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-03-09 14:34:40 +03:00
Roman Khimov
025bf228a2
Merge pull request #3335 from nspcc-dev/TestFailedPreconditionShutdown
rpcsrv: fix TestFailedPreconditionShutdown shutdown
2024-03-06 10:24:30 +03:00
Anna Shaleva
bdcc036073
Merge pull request #3339 from nspcc-dev/workaround-coverage
workflows: workaround Go 1.22 coverage problem
2024-03-06 10:15:58 +03:00
Roman Khimov
d31b01d4b1 workflows: workaround Go 1.22 coverage problem
See https://github.com/golang/go/issues/65653, the fix can be postponed up
to Go 1.23 and we need green.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-03-06 10:03:02 +03:00
Ekaterina Pavlova
ee39b5ca18 rpcsrv: add close of http server in tests
The HTTP server should be closed at the end of the test.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-06 01:17:59 +03:00
Ekaterina Pavlova
46f2da0fb1 rpcsrv: add close of blockchain and rpc server in tests
The logs race issue is a result of improper shutdown during testing.

Close #3217

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-03-06 01:17:59 +03:00
Roman Khimov
b7efccc040
Merge pull request #3333 from nspcc-dev/upd-go-ordered-js
go.mod: better go-ordered-json
2024-03-05 19:29:05 +03:00
Anna Shaleva
a256eac619
Merge pull request #3337 from nspcc-dev/fix-notary-test
notary: fix "Condition never satisfied" in Notary test, fix #2422
2024-03-05 19:11:59 +03:00
Anna Shaleva
261b389e24 go.mod: better go-ordered-json
Almost no functional changes, the most important one is that virtuald
dependency is removed.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-05 19:05:32 +03:00
Anna Shaleva
9e99e35a63
Merge pull request #3338 from nspcc-dev/dep-up
Dependency update
2024-03-05 19:03:28 +03:00
Roman Khimov
b2936e602c notary: fix getCompletedTx error
It checks for any transaction given (like fb), not exactly the main one.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-03-05 19:01:03 +03:00
Roman Khimov
d65b1fd66d *: use v2 LRU, fix #3322
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-03-05 18:39:17 +03:00
Roman Khimov
72ebcbec72 go.mod: update all external dependencies
Except for github.com/urfave/cli which breaks the CLI if upgraded to v1.22.14.
Refs. #3097.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-03-05 18:38:29 +03:00
Roman Khimov
d2a7162217 notary: fix "Condition never satisfied" in Notary test, fix #2422
The theory is:
 * we add a block
 * it triggers notary
 * which can process the fallback before we're to setFinalizeWithError
 * it'll fail and require an additional block to enter, but it's never added
 * FAIL

The solution is:
 * always add an additional block, but treat the first fb specially

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-03-05 18:09:25 +03:00
Roman Khimov
49edf9e498
Merge pull request #3336 from nspcc-dev/go-upd
Add Go 1.22 support, drop Go 1.19 support
2024-03-05 15:40:02 +03:00
Anna Shaleva
8162e9033d *: replace slice.Copy with bytes.Clone
And refactor some code a bit, don't use bytes.Clone where type-specific
helpers may be used instead.

Close #2907.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-05 13:54:10 +03:00
Anna Shaleva
b030c331b0 core: copy SC storage iterator prefix while returning values
It's a bug since Prefix is shared between all iterator items and
appending is not enough. If prefix has enough capacity, then new slice
won't be created and the previous item's prefix will be changed.

This commit fixes the following test failure caused by moving from
bytes.Clone to slice.Copy:
```
 --- FAIL: TestComlileAndInvokeFunction/test_Storage.Find (0.02s)
        --- FAIL: TestComlileAndInvokeFunction/test_Storage.Find/keys_only (0.01s)
            contract_test.go:866:
                	Error Trace:	/home/anna/Documents/GitProjects/nspcc-dev/neo-go/cli/smartcontract/contract_test.go:866
                	Error:      	Not equal:
                	            	expected: []stackitem.Item{(*stackitem.ByteArray)(0xc000a1cdf8), (*stackitem.ByteArray)(0xc000a1ce10)}
                	            	actual  : []stackitem.Item{(*stackitem.ByteArray)(0xc000a1cdb0), (*stackitem.ByteArray)(0xc000a1cdc8)}

                	            	Diff:
                	            	--- Expected
                	            	+++ Actual
                	            	@@ -2,3 +2,3 @@
                	            	  (*stackitem.ByteArray)((len=8) {
                	            	-  00000000  66 69 6e 64 6b 65 79 31                           |findkey1|
                	            	+  00000000  66 69 6e 64 6b 65 79 32                           |findkey2|
                	            	  }),
                	Test:       	TestComlileAndInvokeFunction/test_Storage.Find/keys_only
        --- FAIL: TestComlileAndInvokeFunction/test_Storage.Find/both (0.01s)
            contract_test.go:881:
                	Error Trace:	/home/anna/Documents/GitProjects/nspcc-dev/neo-go/cli/smartcontract/contract_test.go:881
                	Error:      	Not equal:
                	            	expected: []stackitem.Item{(*stackitem.ByteArray)(0xc000515920), (*stackitem.ByteArray)(0xc000515938)}
                	            	actual  : []stackitem.Item{(*stackitem.ByteArray)(0xc000515848), (*stackitem.ByteArray)(0xc000515860)}

                	            	Diff:
                	            	--- Expected
                	            	+++ Actual
                	            	@@ -2,3 +2,3 @@
                	            	  (*stackitem.ByteArray)((len=8) {
                	            	-  00000000  66 69 6e 64 6b 65 79 31                           |findkey1|
                	            	+  00000000  66 69 6e 64 6b 65 79 32                           |findkey2|
                	            	  }),
                	Test:       	TestComlileAndInvokeFunction/test_Storage.Find/both
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-05 13:54:10 +03:00
Anna Shaleva
1560df6913 *: add nolint comment to deprecated math/rand usages
They are used in tests only.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-05 13:54:10 +03:00
Anna Shaleva
0c6627f13d *: use multierror wrapping where possible
Revert 5f6c01336c, remove all multierror
related nolint comments and use multierror wrapping instead.

Close #2906.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-05 13:54:10 +03:00
Anna Shaleva
13ff95a3d3 go.mod: upgrade minimum required Go version to 1.20
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-05 13:54:10 +03:00
Anna Shaleva
5485cf60da Dockerfile: switch to Go 1.22 based images
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-05 13:53:58 +03:00
Anna Shaleva
3f772c2711 workflows: use newer Go 1.22, drop Go 1.19
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-05 11:43:23 +03:00
Anna Shaleva
c660a6e8f3 workflows: remove cache argument from setup-go action
`actions/setup-go@v5` doesn't have `cache` argument.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-05 11:43:23 +03:00
Anna Shaleva
90db72abc9 workflows: upgrade runners
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-05 11:42:53 +03:00
Roman Khimov
8d67f17943
Merge pull request #3332 from nspcc-dev/fix-nep17-test
cli: fix race in TestNEP17Balance
2024-03-03 15:27:25 +03:00
Anna Shaleva
46a3ff3348 *: regenerate all wallets with adjusted parameters
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-01 19:19:03 +03:00
Anna Shaleva
9525bc7785 wallet: fix scrypt parameters in wallet regeneration tests
Default NEP2 scrypt parameters should be overriden where needed,
otherwise our regeneration tests won't generate proper wallets.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-01 19:19:03 +03:00
Anna Shaleva
685d095fa4 cli: fix race in TestNEP17Balance
`wallet1_solo.json` can't be used in this test because it contains
committee member that receives reward for accepted blocks. The race in
this test happens due to the  fact that it uses running blockchain and
checks expected GAS balance via call to blockchain's
GetUtilityTokenBalance API. This call is racy with the CLI command
executed prior to the call which causes the following test failure:
```
2023-04-06T08:44:08.6038406Z === NAME  TestNEP17Balance/all_accounts
2023-04-06T08:44:08.6038738Z     executor.go:240:
2023-04-06T08:44:08.6039454Z         	Error Trace:	/opt/github-runner/_work/neo-go/neo-go/cli/nep_test/executor.go:240
2023-04-06T08:44:08.6040628Z         	            				/opt/github-runner/_work/neo-go/neo-go/cli/nep_test/executor.go:236
2023-04-06T08:44:08.6041787Z         	            				/opt/github-runner/_work/neo-go/neo-go/cli/nep_test/nep17_test.go:73
2023-04-06T08:44:08.6042389Z         	Error:      	Expect "	Amount : 1" to match "^\s*Amount\s*:\s*1.5$"
2023-04-06T08:44:08.6042865Z         	Test:       	TestNEP17Balance/all_accounts
```

The fix is do not use committee accounts for balance checks. Let's use
side accounts and transfer funds to some of them before the test start.
Close #2960.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-03-01 19:19:02 +03:00
Anna Shaleva
1f4e1922ee cli: add new testing wallet
It contains several simple signature accounts that are not related to
network committee or validators. Needed for tests, existing
`testwallet.json` can't de reused since some tests need testing wallet
with a single account.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-02-29 23:48:10 +03:00
Roman Khimov
2404145133
Merge pull request #3331 from nspcc-dev/upd-go-ordered-json
go.mod: upgrade go-ordered-json
2024-02-29 13:36:32 +03:00
Anna Shaleva
e1e2b5304f go.mod: upgrade go-ordered-json
Fetch C# node compatibility fixes for the rest of corner cases. Ref.
https://github.com/nspcc-dev/go-ordered-json/pull/11.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-02-29 13:31:06 +03:00
Roman Khimov
9d7357c9fd
Merge pull request #3329 from nspcc-dev/support-rpc-maps 2024-02-28 16:26:29 +03:00
Anna Shaleva
132531fabe rpcsrv: support Map parameter in invokefunction RPC handler
We have smartcontract.ParameterPair structure that can be properly
marshalled and passed to RPC server as an element of smartcontract.Map
structure. However, RPC server can't unmarshal map values properly
without this change.

This change is compatible with C# node.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-02-28 15:54:33 +03:00
Anna Shaleva
6a560b9a95
Merge pull request #3330 from nspcc-dev/add-macos
Add ARM-based MacOS tests
2024-02-28 12:39:17 +03:00
Roman Khimov
630bd29b8d workflows: drop manual go mod downloads
It's done automatically since like forever, these steps are useless.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-02-28 12:09:15 +03:00
Roman Khimov
5fcae176b8 workflows: add MacOS 14 runner for tests
It's ARM-based, so it's a very nice combination.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-02-28 12:08:13 +03:00
Roman Khimov
cc38221d77
Merge pull request #3307 from nspcc-dev/test-register-peers
services: fix logging data race after shutdown
2024-02-27 17:09:08 +03:00
Ekaterina Pavlova
5cf0c75744 network: fix server shutdown by waiting for goroutines to finish
s.Shutdown() does not wait for all goroutines of the node server to
finish normally just because the server exits without dependent
goroutines awaiting. Which causes logs to attempt to write after the
test has ended. The consequence of this bug fix is that corresponding
tests are fixed.

Close #2973
Close #2974

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-02-27 15:10:51 +03:00
Ekaterina Pavlova
5bb7c6b715 services: update logs flush after services shutdown
Added sync logs for every service separately to provide the ability to
have a custom logger for each service. This commit makes the code follow
the zap usages rules: `Sync calls the underlying Core's Sync method,
flushing any buffered log entries. Applications should take care to
call Sync before exiting.`

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-02-27 15:10:51 +03:00
Ekaterina Pavlova
9b540770cd network: fix typo
Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-02-27 15:10:51 +03:00
Ekaterina Pavlova
775c56e87e network: ensure server is started and shut down only once
Use started atomic.Bool field to ensure that the node server shutdown
procedure is executed only once. Prevent the following panic caused by
server double-shutdown in testing code:
```
--- FAIL: TestServerRegisterPeer (0
.06s)
 panic: closed twice
 goroutine 60 [running]:
 testing.tRunner.func1.2({0x104c40b20, 0x104d0ec90})
 	/opt/homebrew/opt/go/libexec/src/testing/testing.go:1545 +0x1c8
 testing.tRunner.func1()
 	/opt/homebrew/opt/go/libexec/src/testing/testing.go:1548 +0x360
 panic({0x104c40b20?, 0x104d0ec90?})
 	/opt/homebrew/opt/go/libexec/src/runtime/panic.go:914 +0x218
 github.com/nspcc-dev/neo-go/pkg/network.(*fakeTransp).Close
 (0x14000159e08?)
 	/Users/ekaterinapavlova/Workplace/neo-go/pkg/network
 	/discovery_test.go:83 +0x54
 github.com/nspcc-dev/neo-go/pkg/network.(*Server).Shutdown
 (0x14000343400)
 	/Users/ekaterinapavlova/Workplace/neo-go/pkg/network/server.go:299
 	 +0x104
 github.com/nspcc-dev/neo-go/pkg/network.startWithCleanup.func1()
 	/Users/ekaterinapavlova/Workplace/neo-go/pkg/network/server_test
 	.go:408 +0x20
 testing.(*common).Cleanup.func1()
 	/opt/homebrew/opt/go/libexec/src/testing/testing.go:1169 +0x110
 testing.(*common).runCleanup(0x1400032c340, 0x14000159d80?)
 	/opt/homebrew/opt/go/libexec/src/testing/testing.go:1347 +0xd8
 testing.tRunner.func2()
 	/opt/homebrew/opt/go/libexec/src/testing/testing.go:1589 +0x2c
 testing.tRunner(0x1400032c340, 0x104d0c5d0)
 	/opt/homebrew/opt/go/libexec/src/testing/testing.go:1601 +0x114
 created by testing.(*T).Run in goroutine 1
 	/opt/homebrew/opt/go/libexec/src/testing/testing.go:1648 +0x33c
```

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-02-27 15:10:51 +03:00
Ekaterina Pavlova
4715e523e0 services: move blockchain/mempool subscriptions to separate routine
Start of some services is bound to blockchain subscriptions, and thus,
can't be run before the blockchain notifications dispatcher.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-02-27 15:10:51 +03:00
Ekaterina Pavlova
f8dc5ec44f network: change server Start() behavior
Previously user should Start server in a separate goroutine. Now
separate goroutine is created inside the Start(). For normal server
operation, the caller should wait for Start to finish. Also, fixed
TestTryInitStateSync test which was exiting earlier than logs are
called.

Close #3112

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-02-27 15:10:51 +03:00
Roman Khimov
224808975b
Merge pull request #3328 from nspcc-dev/mod-upd
.github: use minimum required Go version from go.mod
2024-02-27 14:02:42 +03:00
Anna Shaleva
8ab08c6221 github: reorder actions/checkout and actions/setup-go steps
Otherwise setup-go action won't work with go-version-file. Ref.
https://github.com/actions/setup-go/issues/340.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-02-27 11:56:49 +03:00
Anna Shaleva
e55809f198
Merge pull request #3327 from nspcc-dev/fix-rpcclient-doc
rpcclient: fix address used in doc
2024-02-27 11:43:42 +03:00
Anna Shaleva
a81804e296 .github: use minimum required Go version from go.mod
For linter job only, port
e0ec4d24cb.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-02-27 11:39:51 +03:00
Roman Khimov
9d3258495f rpcclient: use better RPC endpoint for example
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-02-26 23:18:45 +03:00
Roman Khimov
e09fc00188 rpcclient: fix address used in doc
This one doesn't really work now, it's Legacy. Replace with something N3-ish.

Thanks @lock9 for reporting.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-02-26 22:18:32 +03:00
Anna Shaleva
be17924ef8
Merge pull request #3325 from stepanovdmitrii/fix/tcp_peer_deadlock
tcp_peer: Fix possible goroutine leak
2024-02-26 12:12:28 +03:00
Dmitrii Stepanov
6147bf452a tcp_peer: Fix possible goroutine leak
Scenario:
1. Two messages were read from the connection `p.conn`
2. The first message has started to be processed
3. The second message was queued to be added to the channel `p.incoming`
4. Processing of the first message failed with an error
5. TCP peer is closed, but processing of the second message continues

Signed-off-by: Dmitrii Stepanov <dima-stepan@yandex.ru>
2024-02-25 22:38:18 +03:00
Anna Shaleva
327e766cd9
Merge pull request #3321 from nspcc-dev/leveldb-windows
vm: fix exit in vm tests
2024-02-21 19:47:07 +03:00
Ekaterina Pavlova
b6a65e4d80 cli: fix exit in vm test
Add exit function at the end of the test to prevent
errors in t.Cleanup of the t.TempDir for levelDB instance.

Close #3154

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-02-21 13:22:38 +03:00
Anna Shaleva
00a1a8da56
Merge pull request #3320 from nspcc-dev/update-actions
workflows: update actions
2024-02-20 13:16:20 +03:00
Roman Khimov
07b2de73cd workflows: update actions
I'm tired of warnings for our workflow runs.

The only unupdated is Codecov, we can't switch to token-based uploads at the
moment (and it's required for new version).

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-02-19 22:14:24 +03:00
Roman Khimov
f94df6c013
Merge pull request #3318 from nspcc-dev/TestContractInitAndCompile 2024-02-19 21:49:22 +03:00
Ekaterina Pavlova
5128b84e1d *: update go.mod
According to https://go.dev/doc/modules/gomod-ref go version should be
placed before `require` section.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-02-19 19:12:21 +03:00
Ekaterina Pavlova
5d425a6e45 smartcontract: fix go version mismatch in TestContractInitAndCompile
Needs to updated dependencies inside the test for go1.18 and higher to
match with interop module.

Close #3152

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-02-19 19:08:36 +03:00
Anna Shaleva
71fb759c0d
Merge pull request #3313 from nspcc-dev/TestRun_WithNewVMContextAndBreakpoints
config: fix windows paths in VM tests
2024-02-15 11:07:04 +03:00
Ekaterina Pavlova
588e911ad6 config: fix TestRun_WithNewVMContextAndBreakpoints path for windows
Fix VM test for windows. We don't have notary enabled in unit testchains
 so it was removed.

Close #3309

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-02-14 13:22:07 +03:00
Roman Khimov
5fe4778b2e
Merge pull request #3306 from nspcc-dev/test-windows-path
config: fix TestGetConfigFromContext on Windows
2024-02-14 11:24:48 +03:00
Ekaterina Pavlova
939631c3f9 config: fix TestGetConfigFromContext on Windows
Failing test caused by hardcoded relative path check which is different
for Windows.

Close #3305

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-02-12 19:37:26 +03:00
Roman Khimov
51ac153a7b
Merge pull request #3293 from nspcc-dev/import-multisig
cli: update import-multisig with making --wif optional
2024-01-27 11:26:47 +03:00
Roman Khimov
9d95a2691b
Merge pull request #3291 from nspcc-dev/nns_wrapper 2024-01-27 11:25:50 +03:00
Ekaterina Pavlova
57aa05add3 wallet: make --wif optional in import-multisig command
We have a full list of public keys in the import-multisig command, so if
 we have a key in the wallet that corresponds to one of these keys
 (simple sig), just reuse it for the account automatically

Closes #3266

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-01-26 18:36:29 +03:00
Ekaterina Pavlova
000109bfd1 smartcontract: update nns wrapper
Added missing function from smart-contract manifest.

Close #2732

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-01-26 18:30:17 +03:00
Anna Shaleva
36b89215ab
Merge pull request #3299 from nspcc-dev/autogeneration-linter
smartcontract: fix generation of nns wrapper for follow Go naming
2024-01-26 12:50:35 +03:00
Roman Khimov
a19f85ba34
Merge pull request #3297 from nspcc-dev/sc-convertible
smartcontract: introduce Convertible interface
2024-01-25 17:16:47 +03:00
Anna Shaleva
161b83fd7f rpcclient: ensure nns.RecordType can be passed as a parameter to invoker
Implement smartcontract.Convertible for nns.RecordType.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-01-25 17:04:21 +03:00
Ekaterina Pavlova
9b7eff18c0 smartcontract: fix generation of nns wrapper for follow Go naming
Autogenerated RPC wrapper used underscores to differentiate between
methods/event overloads. Now it adds increasing suffices instead.

Close #3296

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-01-24 16:21:36 +03:00
Anna Shaleva
a22a7177e3 smartcontract: improve TestParameterFromValue
Run error cases in the same loop with test cases. No functional changes.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-01-23 16:09:58 +03:00
Anna Shaleva
b90c0ece87 smartcontract: introduce Convertible interface
Allow to pass Convertible to NewParameterFromValue. Close #3285.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-01-23 16:09:57 +03:00
Anna Shaleva
ef99a7a9e3
Merge pull request #3294 from nspcc-dev/config-validation
config: update validation with check committee
2024-01-22 12:09:17 +03:00
Ekaterina Pavlova
5f745dff72 config: update validation with check committee
ProtocolConfiguration section must include stand by committee and the
number of validators or committee/validators history.

Close #3247

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-01-22 10:25:23 +03:00
Anna Shaleva
ed73628100
Merge pull request #3289 from nspcc-dev/rel-0.105.1
CHANGELOG: release 0.105.1
2024-01-12 15:37:46 +05:00
Anna Shaleva
d20775dd30 CHANGELOG: release 0.105.1
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-01-12 13:35:40 +03:00
Roman Khimov
d428cfc4f1
Merge pull request #3290 from nspcc-dev/ntr-log
services: improve notary service logging
2024-01-12 13:23:00 +03:00
Anna Shaleva
32fab1adf1
Merge pull request #3286 from nspcc-dev/quotes
Upgrade go-ordered-json version
2024-01-12 14:30:12 +05:00
Anna Shaleva
2c0c111fd5
Merge pull request #3287 from nspcc-dev/additional-networking-debugs
Additional networking debugs
2024-01-12 14:29:18 +05:00
Anna Shaleva
ef9f75547a services: improve notary service logging
Let the user know whether it's main or fallback transaction that failed
to be relayed to the network.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-01-12 12:25:11 +03:00
Roman Khimov
f9a82ae45f network: add debug for transactions as well
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-01-12 12:18:06 +03:00
Roman Khimov
db2e214f7e network: add debug for notary payloads
Can be handy if things go wrong.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2024-01-12 12:18:06 +03:00
Ekaterina Pavlova
baac738ec3 smartcontract: add test of extraToStackItem with double quotes
C# double quotes marshalling compatibility test.

Refs #3284

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-01-12 11:18:24 +03:00
Ekaterina Pavlova
188a5e6a8f *: upgrade go-ordered-json version
Ref. nspcc-dev/go-ordered-json/pull/9 needed for C# double quotes
marshalling compatibility.

Closes #3284

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2024-01-12 11:17:25 +03:00
Anna Shaleva
d901697615
Merge pull request #3282 from nspcc-dev/rel-0.105.0
CHANGELOG: release 0.105.0
2023-12-29 18:33:44 +05:00
Anna Shaleva
2da728d176 CHANGELOG: release 0.105.0
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-12-29 16:31:23 +03:00
Anna Shaleva
012da4501d ROADMAP: update release roadmap
Drop deprecated plans, add new ones.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-12-29 16:20:40 +03:00
Anna Shaleva
d8320372b8
Merge pull request #3283 from nspcc-dev/waiter-refactor
waiter: refactor naming and implement header-based WS transactions awaiting
2023-12-29 18:05:27 +05:00
Anna Shaleva
f5b1bd3978 waiter: adopt headers subscription for WS-based tx awaiting
Try to subscribe for headers firstly, and then if RPC server doesn't
have this ability, fallback to block subscriptions to manage transaction
awaiting.

Close #3260.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-12-29 16:00:56 +03:00
Anna Shaleva
7c9b1d05d2 rpcclient: refactor waiter package naming
Adjust names of all used structures, no need to duplicate `Waiter` everywhere,
we already in the `waiter` package. Also, adjust comments to Actor so that links
to Waiter are properly described in docs.

Ref. #3265.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-12-29 15:22:50 +03:00
Anna Shaleva
1ca7b0bbeb
Merge pull request #3265 from nspcc-dev/cli_await
cli: add await flag for operations with transactions
2023-12-29 17:22:23 +05:00
Ekaterina Pavlova
0ffa24932b cli: add await flag for operations with transactions
New --await flag is an option to synchronize on transaction execution
for CLI commands.

Closes #3244

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-29 15:14:16 +03:00
Anna Shaleva
0d3f749b5e
Merge pull request #3274 from fyfyrchik/partial-iterator
Allow to partially unwrap session iterator
2023-12-29 16:21:18 +05:00
Evgenii Stratonikov
78050e8b2c unwrap: Add test for HALT state with an empty stack
Missing piece for perfect coverage. Check that an error is returned an
no panic occurs.

Signed-off-by: Evgenii Stratonikov <fyfyrchik@runbox.com>
2023-12-29 10:50:46 +03:00
Evgenii Stratonikov
4b7b71ce25 vm: Add tests for iterator unwrap scripts
Check that is uses only 3 syscalls and also specify boundary behaviour.

Signed-off-by: Evgenii Stratonikov <fyfyrchik@runbox.com>
2023-12-29 10:50:43 +03:00
Evgenii Stratonikov
402a73b7f3 unwrap: Add ArrayAndSessionIterator(), close #3272
It can be used to work with the results of
CreateCallAndPrefetchIteratorScript() execution. The first item must be
an array and the optional second item must be an iterator, containing
remaining elements.

Signed-off-by: Evgenii Stratonikov <fyfyrchik@runbox.com>
2023-12-29 10:50:39 +03:00
Evgenii Stratonikov
ba1417397f smartcontract: Add CreateCallAndPrefetchIteratorScript()
There is CreateCallAndUnwrapIteratorScript() which can traverse
iterator for nodes with sessions disabled. For other nodes this may
still be beneficial: if there is a small number of items, we might read
(or prefetch) all of them in one request. However, this script continues
to work even for large collections, returning both accumulated array and
remaining iterator.

Signed-off-by: Evgenii Stratonikov <fyfyrchik@runbox.com>
2023-12-29 10:49:53 +03:00
Ekaterina Pavlova
4f5e3f363a cli: fix canceltx ValidUntilBlock parameter of conflicting transaction
If main transaction is known, then conflicting transaction shouldn't be
valid longer than the main one.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-28 15:30:15 +03:00
Ekaterina Pavlova
4c6dca876c rpcclient: move Waiter to a separate package
There are use-cases when not only Actor, but also Invoker and even
simple RPC client must wait (e.g. sendtx or dumptx CLI commands). Actor
requires optional signers in constructor, and it's not always
appropriate to create Actor only to be able to use Waiter, sometimes
it's needed to use only Waiter without Actor.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-28 15:30:15 +03:00
Ekaterina Pavlova
28f1beff64 rpcclient: export NewWaiter function
Change first argument of NewWaiter to be able to directly accept RPC
Client and export for external usage.

Refs #3244.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-28 15:30:15 +03:00
Anna Shaleva
3176f72878
Merge pull request #3258 from nspcc-dev/rpc_validation
rpc: subscription filters validity check
2023-12-28 15:49:59 +05:00
Ekaterina Pavlova
cc06674253 neorpc: add WS notification filter IsValid functionality
Additional check of filters parameters added for filter validation.

Closes #3241.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-28 11:08:46 +03:00
Ekaterina Pavlova
275e814271 rpc: change the type of BlockFilter.Primary from int to byte
BlockFilter has PrinaryIndex of int type while block.Block structure
itself has PrimaryIndex of byte. It's needed to prevent changing
filters field type and all associated subscriptions logic on
server side.

Refs #3241.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-25 18:24:06 +03:00
Anna Shaleva
3283fda790
Merge pull request #3277 from nspcc-dev/add-label-doc
docs: minimally outline local labels
2023-12-25 17:00:12 +05:00
Anna Shaleva
6c88fccc64
Merge pull request #3280 from nspcc-dev/do_not_edit
smartcontract: fix DO NOT EDIT warning to autogenerated files
2023-12-25 16:56:11 +05:00
Ekaterina Pavlova
1237c719e3 smartcontract: fix DO NOT EDIT warning to autogenerated files
The text must appear as the first line of a properly formatted Go //
comment, and that comment must appear before but not be attached to the
package clause and before any /* */ comment.

Closes #3254

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-25 13:01:36 +03:00
Roman Khimov
9015215228
Merge pull request #3252 from nspcc-dev/header_added
rpc: add header_of_added_block event subscription
2023-12-22 15:18:24 +03:00
Ekaterina Pavlova
5d514538cf rpc: add new header_of_added_block event subscription
New event is to notify the user about header's content by the moment
when block is stored (which happens after block's processing). This is
needed for proper Waiter work.

Closes #2751.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-22 15:14:01 +03:00
Roman Khimov
56d32a010e
Merge pull request #3256 from fyfyrchik/fix-signer
Allow complex contract signature schemes in `wallet.Account`
2023-12-21 22:50:57 +03:00
Roman Khimov
a872c200b0
Merge pull request #3279 from nspcc-dev/fix-next-vals-panic
native: prevent improper Neo cache invalidation
2023-12-21 22:17:43 +03:00
Anna Shaleva
47aefad7ea consensus: remove unnecessary call to ComputeNextBlockValidators
dBFT doesn't use validators got from this call to GetValidators callback,
because NeoGo doesn't properly set WithGetConsensusAddress, and thus
this call can be safely skipped. Instead, NeoGo fills NextConsensus field
by itself in NewBlockFromContext callback.

This commit technically doesn't perform any functional changes and doesn't
affect the problem described in #3253 in any way. This commit is just a
removal of the code that was never used by NeoGo library.

This commit is a direct consequence of https://github.com/nspcc-dev/dbft/issues/84.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-12-21 18:16:34 +03:00
Anna Shaleva
d7d850ac7d native: never set Neo's newEpoch* cache values to nil
We have cache update mechanism (Neo's cache votesChanged flag), it must
be used for current epoch and new epoch cached values update. And the
cached current/new epoch values themselves must always contain valid
information for the current/new epoch. These cached values must only be
changed once per epoch, never set them to nil.

This commit prevents CN node panic described in #3253 when dBFT tries
to retrieve new epoch validators with some votes modifications made
before at the same dBFT epoch.

Close #3253.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-12-21 17:56:07 +03:00
Roman Khimov
b62541b6a3 docs: minimally outline local labels
Fixes #2707.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-12-21 13:25:34 +03:00
Evgenii Stratonikov
c8ff44560e neotest: reuse wallet.Account for contract signers
Refs #3245
Refs #3233

Signed-off-by: Evgenii Stratonikov <fyfyrchik@runbox.com>
2023-12-21 11:27:41 +03:00
Evgenii Stratonikov
962b161652 wallet: allow complex contract verification schemes, close #3015
This was recently added in neotest, but working with the real RPC is
still not enjoyable. This commit extends `wallet.Account` with
invocation script builder to aid network fee calculations and signing.

Signed-off-by: Evgenii Stratonikov <fyfyrchik@runbox.com>
2023-12-21 11:26:55 +03:00
Roman Khimov
de98b39a95
Merge pull request #3269 from nspcc-dev/dependabot/go_modules/golang.org/x/crypto-0.17.0
build(deps): bump golang.org/x/crypto from 0.14.0 to 0.17.0
2023-12-19 09:03:39 +03:00
Roman Khimov
2df0ba7c10
Merge pull request #3270 from nspcc-dev/dependabot/go_modules/examples/zkp/cubic_circuit/golang.org/x/crypto-0.17.0
build(deps): bump golang.org/x/crypto from 0.14.0 to 0.17.0 in /examples/zkp/cubic_circuit
2023-12-19 09:03:20 +03:00
Roman Khimov
bcee8c268c
Merge pull request #3271 from nspcc-dev/dependabot/go_modules/examples/nft-nd-nns/golang.org/x/crypto-0.17.0
build(deps): bump golang.org/x/crypto from 0.14.0 to 0.17.0 in /examples/nft-nd-nns
2023-12-19 09:03:00 +03:00
dependabot[bot]
0baa35ed77
build(deps): bump golang.org/x/crypto in /examples/nft-nd-nns
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-18 23:42:52 +00:00
dependabot[bot]
ad122aec41
build(deps): bump golang.org/x/crypto in /examples/zkp/cubic_circuit
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-18 23:40:58 +00:00
dependabot[bot]
ead5b3dc09
build(deps): bump golang.org/x/crypto from 0.14.0 to 0.17.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-18 23:34:02 +00:00
Roman Khimov
3766206f44
Merge pull request #3255 from smallhive/3177-wallet-from-bytes
wallet: Add new wallet constructors
2023-12-14 18:45:44 +03:00
Evgeny Baydakov
2012c56031
wallet: Add new wallet constructors
Closes #3177

Signed-off-by: Evgeny Baydakov <e.bajdakov@gmail.com>
2023-12-12 08:33:30 +04:00
Roman Khimov
a5a87a72c2
Merge pull request #3261 from nspcc-dev/fix-client-init-test
rpcclient: fix failing initialisation-based tests
2023-12-11 13:11:10 +03:00
Anna Shaleva
d5dee8fc94 rpcclient: fix failing initialisation-based tests
Must be a part of #3257.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-12-11 12:41:56 +03:00
Anna Shaleva
6f3a219d67
Merge pull request #3235 from nspcc-dev/actor_refactor
cli: move actor handling
2023-12-11 12:19:33 +05:00
Anna Shaleva
bbbb12af20
Merge pull request #3236 from nspcc-dev/filter_NotaryRequestEvents
rpc: add an ability to filter out NotaryRequestEvents
2023-12-11 12:19:10 +05:00
Ekaterina Pavlova
3fd48a743e rpc: add an ability to filter out NotaryRequestEvents
Add new filter NotaryRequestFilter, support for filtering
NotaryRequestEvents by mempoolevent.Type
(added or removed).

Closes #2425.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-09 11:37:25 +03:00
Roman Khimov
afca64f164
Merge pull request #3257 from nspcc-dev/check-init
rpcclient: check network initialisation for blocks subscriptions
2023-12-08 22:40:08 +03:00
Anna Shaleva
21ccb1a02a rpcclient: check network initialisation for blocks subscriptions
StateRootInHeader depends on it, so we better immediately return error
if client is not initialised.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-12-08 21:57:40 +03:00
Ekaterina Pavlova
44e21c9a8e cli: optimize CosignersSeparator check in loops
No functional changes.
We have 2 exactly the same cycles,and in the 1st cycle we set
cosignersOffset to the right value. So we don't need to check for arg ==
 cmdargs.CosignersSeparator one more time.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-07 10:37:01 +03:00
Ekaterina Pavlova
8bdbac3c5e cli: move actor-related functions handling to options package
Move actor handling into CLI package.
GetRPCWithActor returns RPC with actor instances.

Close #2682.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-07 10:35:37 +03:00
Ekaterina Pavlova
d7cab3b82c cli: move wallet-related flags handling to options package
Move GetAccFromContext, GetUnlockedAccount, ReadWalletConfig handling
into options package to reuse this code from all CLI handlers.
getDecryptedAccount is replaced by GetUnlockedAccount.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-06 10:49:50 +03:00
Ekaterina Pavlova
f93e2fbba4 cli: use (*transaction.Transaction).HasSigner where possible
No functional changes.
tx.HasSigner usage to avoid code duplication.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-06 10:49:50 +03:00
Anna Shaleva
441eb8aa86
Merge pull request #3250 from nspcc-dev/bbolt
go.mod: upgrade BoltDB to 1.3.8
2023-12-06 11:18:02 +05:00
Anna Shaleva
af0d1fe3c9
Merge pull request #3251 from nspcc-dev/mac
github: enable amd64 builds for osx
2023-12-06 11:16:44 +05:00
Ekaterina Pavlova
cab358dba1 github: enable amd64 builds for osx
Enable AMD64 builds for Intel based OSX.

Closes #3238.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-12-05 21:49:10 +03:00
Roman Khimov
0639cedd05 go.mod: upgrade BoltDB to 1.3.8
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-12-05 21:01:44 +03:00
Roman Khimov
9a270ae30c
Merge pull request #3233 from stepanovdmitrii/feat/neotest_contract_signer_support
neotest: Add contract signer support
2023-12-04 10:03:49 +03:00
Dmitrii Stepanov
7b53a0c239 neotest: Add contract signer support
Signed-off-by: Dmitrii Stepanov <dima-stepan@yandex.ru>
2023-12-01 10:50:08 +03:00
Roman Khimov
6c0c2a6a98
Merge pull request #3246 from nspcc-dev/fix-doc
neotest: adjust Signer documentation
2023-12-01 10:23:46 +03:00
Roman Khimov
26f96fe7ee
Merge pull request #3243 from nspcc-dev/add-management-test
native: test immediate contract availability
2023-12-01 10:21:09 +03:00
Anna Shaleva
daa2b3b920 neotest: adjust Signer documentation
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-12-01 09:25:41 +03:00
Roman Khimov
b31d39836a native: test immediate contract availability
I had some reason to suspect something is wrong here (but it's all OK). Even
though this is kinda tested in TestDeployGetUpdateDestroyContract, it uses
internal APIs and with neotest we can ensure it work OK for a complete tx/block
environment. So, won't hurt having these tests as well.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-11-30 15:58:00 +03:00
Roman Khimov
34be76efb7
Merge pull request #3240 from nspcc-dev/fix-native-upd
core: remove UpdateHistory from NativeContract structure
2023-11-29 16:18:34 +03:00
Roman Khimov
90e18ec743
Merge pull request #3242 from nspcc-dev/improve-subs-doc
Improve notification subsystem documentation
2023-11-29 14:35:38 +03:00
Anna Shaleva
e3aa6bba4d docs: add ordering guarantees for notary request events
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-29 14:00:44 +03:00
Anna Shaleva
81a439a0d6 docs: fix typo
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-29 13:55:54 +03:00
Anna Shaleva
6fdda0f15d rpcclient: add doc link to notifications ordering guarantees
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-29 13:53:45 +03:00
Anna Shaleva
8e8936912d core: remove UpdateHistory from NativeContract structure
Although it doesn't raise an exception on our side, we still have this
unrelevant information in the resulting RPC call response structure.
This should be a part of https://github.com/nspcc-dev/neo-go/pull/3212.

Port https://github.com/neo-project/neo-modules/pull/851.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-29 09:25:04 +03:00
Roman Khimov
76261f1605
Merge pull request #3239 from nspcc-dev/ntr-doc-upd
rpcclient: improve documentation
2023-11-28 20:25:08 +03:00
Anna Shaleva
42b84ad905 rpcclient: improve documentation
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-28 20:23:33 +03:00
Roman Khimov
98de5b9ccb
Merge pull request #3237 from nspcc-dev/emit-smth
vm: allow to emit `any` based on its type
2023-11-28 18:01:06 +03:00
Anna Shaleva
b637048122 vm: allow to emit any based on its type
No functional changes, just moved a part of emit.Array to a separate
exported method. It may be useful for contract-based witness invocation
scripts construction and not only. Ref.
https://github.com/nspcc-dev/neo-go/pull/3233#discussion_r1407786333.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-28 17:17:34 +03:00
Roman Khimov
e8e964e3da
Merge pull request #3234 from nspcc-dev/add-response-source
examples: improve cubic circuit documentation
2023-11-28 17:07:12 +03:00
Anna Shaleva
d7b84c0b47 examples: improve ZKP production example
Add more detailed errors and comments.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-28 17:00:34 +03:00
Anna Shaleva
29f344fd9b examples: add one more source of suitable response* files for Groth16
Turns out that Zcash swiched to BLS12-381 since https://github.com/zcash/zcash/issues/2502,
thanks to @EdgeDLT for pointing that out. I've checked that our
TestCubicCircuit_EndToEnd_Prod test passes with response file downloaded
from the attestations page of Zcash ceremony, thus I propose to put theirs
attestations link before the link to PPoT, because PPoT attestations contain
outdated links and not all responses can be downloaded.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-28 17:00:33 +03:00
Roman Khimov
2f9b4a2dbf
Merge pull request #3232 from nspcc-dev/storage-limits
interop: add contract storage limits
2023-11-28 13:19:55 +03:00
Anna Shaleva
2eab743a5b compiler: add compatibility test for storage limits
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-28 10:51:03 +03:00
Anna Shaleva
a159054f10 *: update interop dependency
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-28 10:49:39 +03:00
Anna Shaleva
b35f351f0b interop: add contract storage limits
Users of NeoGo interop package may have a demand to use these limits
for custom purposes, it would be nice to have them as constants.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-27 19:56:13 +03:00
Roman Khimov
fd7b7ffc13
Merge pull request #3231 from nspcc-dev/rel-0.104.0
CHANGELOG: release 0.104.0
2023-11-27 18:14:27 +03:00
Anna Shaleva
a9803b3477 CHANGELOG: release 0.104.0
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-27 17:34:53 +03:00
Roman Khimov
7179efec35
Merge pull request #3223 from nspcc-dev/cancel_command
cli: cancel transaction command
2023-11-27 17:32:48 +03:00
Ekaterina Pavlova
fc77754098 cli: cancel transaction command
CLI side method for canceling not yet accepted transaction. It's
alternative to unsupported `canceltransaction` RPC method.

Close #3151.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-11-27 18:10:54 +04:00
Ekaterina Pavlova
7a2eb32c42 cli: wallet flag set
Wallet operations flags moved to options and joint into Wallet flag set.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-11-25 10:05:05 +04:00
Ekaterina Pavlova
20a57d8337 cli: export GetAccFromContext and GetUnlockedAccount methods
Exported to avoid code duplication.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-11-25 10:05:05 +04:00
Roman Khimov
7a1bf77585
Merge pull request #3229 from nspcc-dev/fix-service-init
core, services: fix Designation-dependant service initialisation
2023-11-24 15:47:42 +03:00
Anna Shaleva
15b4e0a8cd services: adjust StateRoot service initialisation
Perform initialisation of StateRoot service with designated
StateValidator's node list in the service constructor. There's no need
to wait until the next role update event, and it may lead to inaccuraces
in service work on SIGHUP/server restart.

A part of #3228.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-24 15:25:51 +03:00
Anna Shaleva
11ec0db350 core, services: fix Designation-dependant service initialisation
Initialise services dependant on roles designation based on N+1
block so that Genesis roles extension work properly. There's not
much sence to fetch node roles information for the latest persisted
block because Designation contract itself makes designated nodes
responsible since the next subsequent block.

A part of #3228.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-24 15:25:51 +03:00
Roman Khimov
4216efbe6c
Merge pull request #3227 from nspcc-dev/upd-zkp-deps
examples: do not replace neo-go library for ZKP examples
2023-11-24 09:32:58 +03:00
Anna Shaleva
626f1ee198 examples: do not replace neo-go library for ZKP examples
0.103.1 contains all necessary changes to run tests.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-24 09:21:09 +03:00
Anna Shaleva
5d1e0192f1
Merge pull request #3206 from nspcc-dev/relative_path_flag
cli: add --relative-path option
2023-11-24 08:16:16 +03:00
Roman Khimov
1f84756c21
Merge pull request #3222 from nspcc-dev/doc/contracts-storage-seek-call-improvement
doc/Mention prefix trimming in `Seek` operations where applicable
2023-11-23 23:03:20 +03:00
Roman Khimov
61d5b6eb0c
Merge pull request #3221 from nspcc-dev/json-limits
Anti-DOS RPC limitations
2023-11-23 23:02:50 +03:00
Ekaterina Pavlova
f457d50773 cli: add --relative-path option
To be able running the node from any working directory by simply
pointing the relative-path as prefix for relative parameters set in
config.

Closes #3179.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
2023-11-23 21:41:50 +04:00
Anna Shaleva
d511f6e5a9 confi: add MaxRequestHeaderBytes RPC configuration option
A part of #3131, follow the notion of https://github.com/neo-project/neo-modules/pull/827,
but don't restrict request line size due to https://github.com/golang/go/issues/15494.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-23 20:17:49 +03:00
Anna Shaleva
802d8d24b9 config: add MaxRequestBodySize RPC configuration option
A part of #3131, follow the https://github.com/neo-project/neo-modules/pull/827.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-23 20:17:49 +03:00
Roman Khimov
195bb742ca
Merge pull request #3225 from nspcc-dev/ojson-upd
*: upgrade go-ordered-json version
2023-11-23 19:27:24 +03:00
Anna Shaleva
251b8c57b9 *: upgrade go-ordered-json version
Close #3224.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-23 19:14:28 +03:00
Pavel Karpy
62b710868b *: mention prefix trimming in Seek operations where applicable
Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
2023-11-23 18:44:19 +03:00
Anna Shaleva
7362fd94e6
Merge pull request #3220 from nspcc-dev/stable-func-debug-data
compiler: walk over functions in reproducible order, fix #3219
2023-11-23 14:50:01 +03:00
Roman Khimov
341d978e5b compiler: walk over functions in reproducible order, fix #3219
It affects both Debug data and bindings, otherwise two unnamed structures can
get any of unnamed/unnamedx names depending on particular invocation.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-11-23 13:21:51 +03:00
Anna Shaleva
22c654b200 neorpc: restrict maximum subitems number in SignerWithWitness
Restrict the number of Rules, Contracts and Groups. A part of #3131.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-23 12:12:34 +03:00
Anna Shaleva
2f6ba1fded rpcsrv: define GetSignersWithWitnesses on a pointer
Nil receiver can be properly handled and all other `Param`'s mathods
are defined on a pointer.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-23 11:44:29 +03:00
Roman Khimov
25ef2c7f16
Merge pull request #3218 from nspcc-dev/serialization-limits
Introduce stackitem serialization limits
2023-11-22 21:28:25 +03:00
Anna Shaleva
910d53b27b core: do not check manifest size on deploy/update
Manifest will be a part of the state.Contract which will be checked on its
way to the storage. Tiny optimisation which allows not to serialize manifest
twice. Ref. https://github.com/nspcc-dev/neo-go/pull/3218#discussion_r1402374232.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-22 20:17:09 +03:00
Anna Shaleva
1d189fd90c Revert "native: ignore decoding errors during cache init"
This reverts commit 822722bd2e.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-22 19:39:03 +03:00
Anna Shaleva
6824bd9f40 smartcontract: require manifest serialization in (*Manifest).IsValid
Port the restrictive part of https://github.com/neo-project/neo/pull/2948.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-22 19:39:03 +03:00
Anna Shaleva
387c411da0 vm: add default limit to SI serialization context
Follow the notion of https://github.com/neo-project/neo/pull/2948.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-22 19:39:01 +03:00
Roman Khimov
00c6a811ab
Merge pull request #3215 from nspcc-dev/tiny-compiler-fixes
Tiny compiler fixes
2023-11-22 19:29:37 +03:00
Roman Khimov
e21664cd7d
Merge pull request #3216 from nspcc-dev/drop-fyrchik
*: drop fyrchik from code owners
2023-11-22 19:29:28 +03:00
Roman Khimov
23e553f647 *: drop fyrchik from code owners
His account is disabled (which technically leads to an invalid CODEOWNERS
file) and he's no longer active, unfortunately.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-11-22 11:18:27 +03:00
Roman Khimov
4c9cd438f8 rpcbinding: sort named types to stabilize output
Same input -> same output, otherwise tests fail and @AnnaShaleva is annoyed.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-11-21 21:47:51 +03:00
Roman Khimov
eade327b9b compiler: check for pkg nilness, fix #3202
Unfortunately, when import cycle happens somewhere deep in the import chain we
dont't get an error from packages.Load(). But it leaves some imports
uninitialized, so at least we can check for them.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-11-21 21:47:51 +03:00
Roman Khimov
8aeb30e019
Merge pull request #3214 from nspcc-dev/doc-canceltx-rpc
docs: canceltransaction is not going to be supported
2023-11-21 20:29:45 +03:00
Roman Khimov
fced6a27ba compiler: iterate over autoguessed events in reproducible way
Otherwise it's undertermined which of two unnamed structures will get "Unnamed"
and "UnnamedX" which can break the test from time to time.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-11-21 18:43:40 +03:00
Roman Khimov
5370034955 compiler: deduplicate autoguessed event names, fix #3088
Make them stable wrt parameter order and use proper names in event structures
as well.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-11-21 18:35:26 +03:00
Roman Khimov
a5d041a1ac compiler: check range first, analyze funcs then
Type data is added while walking through function ins/outs even if we're to
throw this function away. But we don't need it, these types are not used, so
we can deal with the main part of #3071 by optimizing this out.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-11-21 17:52:17 +03:00
Roman Khimov
7f9e2e5047 cli/sc: don't rewrite RPC bindings by default
TestAssistedRPCBindings didn't respect rewriteExpectedOutputs setting, with
this behavior compiler could produce any result and the test wouldn't notice.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-11-21 17:43:45 +03:00
Roman Khimov
2ae44e074d docs: canceltransaction is not going to be supported
Refs. neo-project/neo-modules#837.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-11-21 16:11:58 +03:00
Roman Khimov
ff958706f4
Merge pull request #3212 from nspcc-dev/drop-history
Move NativeUpdateHistory logic uner hardforks
2023-11-21 15:46:16 +03:00
Roman Khimov
28ee1621b8
Merge pull request #3155 from nspcc-dev/apptr-pricing
*: introduce Policy attributes pricing
2023-11-21 15:44:40 +03:00
Anna Shaleva
58102a9a80 *: move NativeUpdateHistory logic under Hardforks management
Close #3196.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-21 14:05:28 +03:00
Roman Khimov
4d8601297d
Merge pull request #3211 from nspcc-dev/fix-curr-height
core: review usages of (*intero.Context).BlockHeight method
2023-11-21 13:51:03 +03:00
Anna Shaleva
64b5ba24e9 *: fix less then typos everywhere
My poor grammar...

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-21 13:47:59 +03:00
Anna Shaleva
3b11f98cd0 core: review usages of (*intero.Context).BlockHeight method
This method returns persisted block height and doesn't take into account
persisting block height. Some of the callers of this method relay on
the wrong assumption that BlockHeight() returns persisting block index.

Fix improper usages of this method and adjust tests. Ref.
61a066583e/src/Neo/SmartContract/ApplicationEngine.cs (L634).

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-21 13:46:13 +03:00
Anna Shaleva
c6d259b285 *: update interop deps
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-21 13:44:02 +03:00
Anna Shaleva
0493ddbd70 ROADMAP: add new line to the end of the file
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-21 13:42:56 +03:00
Anna Shaleva
474225d425 core, rpcsrv: apply generic attributes fee logic to NotaryServiceFeePerKey
Remove related methods from native Notary and add relevant code to native
Policy.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-21 13:42:56 +03:00
Anna Shaleva
82cb2e718d native: introduce attribute pricing
Port the https://github.com/neo-project/neo/pull/2916.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-21 13:42:56 +03:00
Roman Khimov
80fcf81102
Merge pull request #3209 from nspcc-dev/strict-cfg
Forbid unknown YAML node configuration fields
2023-11-21 13:20:57 +03:00
Roman Khimov
8e5a724f5d
Merge pull request #3210 from nspcc-dev/service-err
wallet: provide more detailed errors on failed NewWalletFromFile
2023-11-21 13:20:11 +03:00
Anna Shaleva
59baecd39b wallet: provide more detailed errors on failed NewWalletFromFile
Close #3180.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-21 13:07:11 +03:00
Roman Khimov
f10d2d2be7
Merge pull request #3208 from nspcc-dev/strlen
Support `strLen` native StdLib method
2023-11-20 21:29:08 +03:00
Anna Shaleva
63de821ff4 config: forbid unknown YAML configuration fields
Close #3128 and fix one of the privnet configurations along the way.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 20:04:09 +03:00
Anna Shaleva
a4779de375 core: improve TestConfigNativeUpdateHistory subtests naming
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 20:03:28 +03:00
Anna Shaleva
0fef119f5f rpcsrv: update test data
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 19:41:45 +03:00
Anna Shaleva
16b7a83f30 *: update interop deps
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 19:25:52 +03:00
Anna Shaleva
406c9f8b92 core, interop: add strLen method for native StdLib contract
Close #3195.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 19:23:33 +03:00
Roman Khimov
b5cf3f592f
Merge pull request #3207 from nspcc-dev/limit-rpc-signers
rpcsrv/params: limit tx signers/witnesses
2023-11-20 16:29:42 +03:00
Roman Khimov
f6cb698cd1 rpcsrv/params: limit tx signers/witnesses
Inspired by https://github.com/neo-project/neo-modules/pull/845.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-11-20 16:01:14 +03:00
Roman Khimov
7fb077e999
Merge pull request #3186 from nspcc-dev/reduce-max-nef-size
Restrict maximum serialized NEF file size
2023-11-20 15:19:40 +03:00
Roman Khimov
48bd8057dd
Merge pull request #3058 from nspcc-dev/current-signers
core: support `System.Runtime.CurrentSigners` syscall
2023-11-20 15:14:05 +03:00
Anna Shaleva
90705e37e9 compiler: perform NEF size check on serialization
Retun an error if the serialized NEF size exceeds stackitem.MaxSize.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 15:14:05 +03:00
Anna Shaleva
06c99fb2af *: update interop deps
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 14:50:30 +03:00
Anna Shaleva
e63a93b8a0 compiler: add tests for System.Runtime.CurrentSigners
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 14:49:07 +03:00
Anna Shaleva
2fba04490a core: add System.Runtime.CurrentSigners syscall
Port the https://github.com/neo-project/neo/pull/2827.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 14:46:27 +03:00
Anna Shaleva
90b01bcea6 core: move SignersToStackItem to transaction package
It will be reused from interops.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 14:46:27 +03:00
Anna Shaleva
14d98811a5 smartcontract: restrict maximum NEF file size on deserialisation
Port https://github.com/neo-project/neo/pull/2939.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 14:32:32 +03:00
Roman Khimov
b2205940fa
Merge pull request #3194 from nspcc-dev/add-test
manifest: add compatibility test for Permissions and Trust serialization
2023-11-18 22:44:57 +03:00
Anna Shaleva
fdcc369d60 manifest: add compatibility test for Permissions and Trust serialization
We already have tests for Permission deserialisation, so port the first
part of https://github.com/neo-project/neo/pull/2948.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-18 13:32:28 +03:00
Roman Khimov
dd48f810cc
Merge pull request #3203 from nspcc-dev/doc-upd
docs: adjust ValidatorsHistory documentation
2023-11-17 17:23:21 +03:00
Anna Shaleva
f88df92925 docs: adjust ValidatorsHistory documentation
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-17 16:57:41 +03:00
Roman Khimov
de2a445088
Merge pull request #3185 from nspcc-dev/fix-stackitem-limits
vm: reduce maximum stckitem size
2023-11-13 22:53:19 +03:00
Roman Khimov
5e220754d7
Merge pull request #3199 from nspcc-dev/fix-err
neorpc: adjust common error messages
2023-11-13 22:17:07 +03:00
Anna Shaleva
b0cdae4666 vm: reduce maximum stckitem size
To prevent possible DoS. Port the https://github.com/neo-project/neo-vm/pull/514,
close #3170.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-13 20:40:30 +03:00
Anna Shaleva
963a22e280 neorpc: adjust common error messages
According to the initial proposal and
https://github.com/neo-project/proposals/pull/156/files#diff-2b5f7c12a23f7dbe4cb46bbf4be6936882f8e0f0b3a4db9d8c58eb294b02e6ed.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-13 20:29:13 +03:00
Roman Khimov
dbd647e3a6
Merge pull request #3193 from nspcc-dev/rel-0.103.1
Release 0.103.1
2023-11-09 10:36:51 +03:00
Anna Shaleva
ed4610f8b4 CHANGELOG: release 0.103.1
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-09 10:28:12 +03:00
Roman Khimov
7045d3bd63
Merge pull request #3192 from nspcc-dev/rpc-err
neorpc: ensure errors.Is and errors.As work properly with neorpc.Error
2023-11-08 09:34:05 +03:00
Roman Khimov
f8d8b03f64
Merge pull request #3191 from nspcc-dev/fix-roundtrip
native: prohibit non-zero GAS/NEO roundtrip with zero balance
2023-11-08 09:32:56 +03:00
Anna Shaleva
fca7eb35a1 neorpc: ensure errors.Is and errors.As work properly with neorpc.Error
Close #3188.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-07 23:59:53 +03:00
Anna Shaleva
b4866bd69e native: prohibit NEP-17 roundtrip with zero balance
Close #3190.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-07 19:37:37 +03:00
Roman Khimov
c5e284c117
Merge pull request #3187 from nspcc-dev/fix-neo-init
Fix native Neo cache initialization
2023-11-03 10:56:02 +03:00
Anna Shaleva
ba4c58780c native: optimize policy check for transaction's signers
Do not retrieve RO cache for each signer, make it ones per transaction
instead.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-03 10:29:47 +03:00
Anna Shaleva
de38163f89 core: log block height before MPT/natives cache initialization
We have this log on the network server side, but it would also be
useful in case of failed blockchain initialization.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-03 10:29:46 +03:00
Anna Shaleva
bbbc6805a8 native: fix NeoToken initialization process
Refactored native NeoToken cache scheme introduced in #3110 sometimes requires
validators list recalculation during native cache initialization process (when
initializing with the existing storage from the block that is preceded each N-th block).
To recalculate validators from candidates, native NeoToken needs an access to
cached native Policy blocked accounts. By the moment of native Neo initialization,
the cache of native Policy is not yet initialized, thus we need a direct DAO access
for Policy to handle blocked account check.

Close #3181.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-02 17:56:02 +03:00
Anna Shaleva
91c8aa21cc core: fix typo in comment
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-02 17:15:34 +03:00
Roman Khimov
8ed6d97085
Merge pull request #3178 from nspcc-dev/dependabot/go_modules/google.golang.org/grpc-1.57.1
build(deps): bump google.golang.org/grpc from 1.57.0 to 1.57.1
2023-10-27 12:25:58 +03:00
dependabot[bot]
c9803f5448
build(deps): bump google.golang.org/grpc from 1.57.0 to 1.57.1
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.57.0 to 1.57.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.57.0...v1.57.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-25 21:37:52 +00:00
Roman Khimov
9de9320d55
Merge pull request #3172 from nspcc-dev/rel-0.103.0
Release 0.103.0
2023-10-20 22:05:51 +03:00
Roman Khimov
b9297a4b2c
Merge pull request #3175 from nspcc-dev/fix-nns-dep
examples: update neo-go dependency and fetch fresh gnark-crypto
2023-10-20 22:04:27 +03:00
Anna Shaleva
a755a2be30 CHANGELOG: release 0.103.0
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-20 21:33:34 +03:00
Anna Shaleva
0e458f473f examples: update neo-go dependency and fetch fresh gnark-crypto
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-20 21:20:45 +03:00
Roman Khimov
d89c8801d6
Merge pull request #3173 from nspcc-dev/dep-upd
*: update interop dependencies
2023-10-20 21:15:54 +03:00
Roman Khimov
dffd87c6c8
Merge pull request #3171 from nspcc-dev/fix-linter
Fix linter problems
2023-10-20 21:14:41 +03:00
Anna Shaleva
1605496002 *: update interop dependencies
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-20 19:38:20 +03:00
Anna Shaleva
7a6b908cae neorpc: fix exported structure comment
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-20 19:31:23 +03:00
Roman Khimov
c3955f87d1
Merge pull request #3165 from nspcc-dev/fix-win-timeout
Improve timeout of RPC tests on Windows
2023-10-20 19:07:24 +03:00
Anna Shaleva
3544d65ecd rpcclient: disable linter for documentation example
Disable the following linter warning:
```
superfluous-else: if block ends with call to panic function, so drop this else and outdent its block (revive)
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-20 17:28:57 +03:00
Anna Shaleva
6e0af5ac90 network: fix linter warning
Fix the following linter warning:
```
dot-imports: should not use dot imports (revive)
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-20 17:23:35 +03:00
Anna Shaleva
39ce3a9d1d vm: fix linter warning
Fix the following linter warning:
```
indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-20 17:22:21 +03:00
Anna Shaleva
c93658b1c1 Partially revert "*: use localhost address instead of 127.0.0.1, fix #2575"
This partially reverts commit c26a962b55 for testing
chains configurations.

Ref. #2975, although this commit doesn't close it. This commit is an attempt to
enforce IPv4 for our test clients to avoid problem described in the issue.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-20 17:17:37 +03:00
Roman Khimov
890f64007a
Merge pull request #3168 from nspcc-dev/roles-init
Introduce Genesis protocol setting extensions
2023-10-19 18:49:45 +03:00
Anna Shaleva
8cc32a91b6 *: add GenesisTransaction extension to the protocol configuration
Provide a script that should be deployed in the genesis block.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-19 18:33:50 +03:00
Anna Shaleva
065bd3f0be *: introduce Genesis protocol configuration
This section contains genesis-related settings including genesis-related or natives-related
extensions. Currently it includes the set of node roles that may be designated
duing the native Designation contract initialisation.

Close #3156.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-19 18:30:20 +03:00
Anna Shaleva
1815bc8a32 *: update Stringers wrt fresh Stringer version
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-19 11:33:07 +03:00
Anna Shaleva
61a74ab331 native: introduce Stringer for noderoles types
And rename roles.go to role.go to match the role_string.go and the
existing naming pattern for enums.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-19 11:33:04 +03:00
Roman Khimov
04d778612e
Merge pull request #3167 from nspcc-dev/autogen-warn
smartcontract: add `DO NOT EDIT` warning to autogenerated files
2023-10-18 21:35:20 +03:00
Roman Khimov
cb0ef2de3d
Merge pull request #3166 from nspcc-dev/find-storage-param
rpcclient: always provide `start` parameter for `findstorage` RPC
2023-10-18 21:32:50 +03:00
Anna Shaleva
3353599b38 cli: adjust usage text of contract generate-rpcwrapper command
Hash is optional since f97eaddf.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-18 20:38:54 +03:00
Anna Shaleva
6476241b3a smartcontract: add DO NOT EDIT warning to autogenerated files
Close #3139.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-18 20:34:36 +03:00
Anna Shaleva
1841d818ec rpcclient: always provide start parameter for findstorage RPC
Close #3137.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-18 20:12:05 +03:00
Roman Khimov
ef2bc7ca04
Merge pull request #3164 from nspcc-dev/pretty-generator
Apply `gofmt` to autogenerated bindings
2023-10-18 18:41:32 +03:00
Anna Shaleva
6a706d5c5a rpcbinding: fix formatting of binding template
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-18 18:15:33 +03:00
Anna Shaleva
c42486587d smartcontract: apply gofmt to the resulting bindings
Close #3133.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-18 18:14:52 +03:00
Roman Khimov
d24579748e
Merge pull request #3162 from nspcc-dev/dependabot/go_modules/examples/zkp/cubic_circuit/github.com/consensys/gnark-0.9.1
build(deps): bump github.com/consensys/gnark from 0.9.0 to 0.9.1 in /examples/zkp/cubic_circuit
2023-10-18 10:40:47 +03:00
dependabot[bot]
19cfbc8d85
build(deps): bump github.com/consensys/gnark
Bumps [github.com/consensys/gnark](https://github.com/consensys/gnark) from 0.9.0 to 0.9.1.
- [Release notes](https://github.com/consensys/gnark/releases)
- [Changelog](https://github.com/Consensys/gnark/blob/master/CHANGELOG.md)
- [Commits](https://github.com/consensys/gnark/compare/v0.9.0...v0.9.1)

---
updated-dependencies:
- dependency-name: github.com/consensys/gnark
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-18 07:20:33 +00:00
Anna Shaleva
b1ad19864f
Merge pull request #3163 from nspcc-dev/dependabot/go_modules/github.com/consensys/gnark-0.9.1
build(deps): bump github.com/consensys/gnark from 0.9.0 to 0.9.1
2023-10-18 10:19:11 +03:00
dependabot[bot]
0bd618bee4
build(deps): bump github.com/consensys/gnark from 0.9.0 to 0.9.1
Bumps [github.com/consensys/gnark](https://github.com/consensys/gnark) from 0.9.0 to 0.9.1.
- [Release notes](https://github.com/consensys/gnark/releases)
- [Changelog](https://github.com/Consensys/gnark/blob/master/CHANGELOG.md)
- [Commits](https://github.com/consensys/gnark/compare/v0.9.0...v0.9.1)

---
updated-dependencies:
- dependency-name: github.com/consensys/gnark
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-17 14:24:56 +00:00
Roman Khimov
38f77c39d0
Merge pull request #3142 from Ayrtat/fix/wsclient_hang
rpcclient: fix wsclient hang on making request
2023-10-16 15:26:13 +03:00
Roman Khimov
1aabdc9672
Merge pull request #3145 from nspcc-dev/gnark-upd
go.mod: upgrade gnark to v0.9.0
2023-10-16 15:25:19 +03:00
Anna Shaleva
545dbbc668 go.mod: upgrade gnark to v0.9.0
Close #3079.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-16 15:06:30 +03:00
Ayrtat
ff19189937 rpcclient: fix #3135 wsclient hangs on making request
* Rename c.done channel to c.readerDone
* Introduce c.writerDone channel that is closed if the wsWriter's loop
  is done
* Make the error returned by makeWsRequests verbose

Signed-off-by: Ayrtat <amper.meter1775@gmail.com>
2023-10-16 13:01:12 +03:00
Roman Khimov
a9a848a306
Merge pull request #3160 from nspcc-dev/add-version-hf
rpcsrv: add hardforks to `getversion` response
2023-10-16 10:37:10 +03:00
Anna Shaleva
69a0104d05 rpcsrv: add hardforks to getversion response
Port https://github.com/neo-project/neo-modules/pull/823.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-16 10:33:21 +03:00
Roman Khimov
f31e3f70aa
Merge pull request #3157 from nspcc-dev/upd-go
*: drop go 1.18 support, add go 1.21 support
Close #2626, close #2627, close #2629.
2023-10-12 23:37:01 +03:00
Anna Shaleva
c8ed629b5d
Merge pull request #3158 from nspcc-dev/dependabot/go_modules/golang.org/x/net-0.17.0
build(deps): bump golang.org/x/net from 0.14.0 to 0.17.0
2023-10-12 18:33:30 +03:00
Anna Shaleva
645076d04f examples: update neo-go dependency
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-12 18:19:30 +03:00
Anna Shaleva
3c13a3d74d *: update interop deps
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-12 18:09:08 +03:00
Anna Shaleva
e06051e14c cli: use fmt.Append* where possibble
Close #2629.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-12 18:07:54 +03:00
Anna Shaleva
3aa858a69f *: drop go 1.18 support in doc and build targets
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-12 17:59:42 +03:00
Anna Shaleva
241d5f593e *: use methods of binary.AppendByteOrder where applicable
We often use binary.PutUint*, but almost all these cases have preallocated
buffer of the size that matches exactly the desired one and use a single or
a couple of calls to PutUint*. Thus, I don't think that replacing
binary.PutUint* by AppendUint* will make things better for all these usages.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-12 17:59:42 +03:00
Anna Shaleva
dc3d1300dd *: replace go.uber.org/atomic with sync/atomic
Use sync/atomic everywhere and exclude go.uber.org/atomic from go.mod.
Close #2626.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-12 17:59:34 +03:00
Anna Shaleva
7ca4ce0f79 core: fix race in stateroot initialization error logging
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-12 13:37:31 +03:00
Anna Shaleva
9cd5c88077 Dockerfile.wsc: use official golang image for Windows NeoGo image
Don't need to keep the copy of the official Golang image in our
dockerfile, let's use it as a base builder image.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-12 13:28:59 +03:00
Anna Shaleva
45dcf38563 .github, Dockerfiles: bump minimum\maximum go versions
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-12 13:28:59 +03:00
Anna Shaleva
995d774ff8 *: bump minimum required go version to 1.19
For all components.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-12 13:28:59 +03:00
Anna Shaleva
e6b4fbc999 rpcsrv: format code
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-12 13:28:59 +03:00
dependabot[bot]
6e9ac29d5c
build(deps): bump golang.org/x/net from 0.14.0 to 0.17.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-11 23:07:53 +00:00
Roman Khimov
b284b902d6
Merge pull request #3138 from nspcc-dev/fix-conflicts
*: refactor Notary conflict records storage scheme
2023-10-10 18:09:20 +03:00
Anna Shaleva
32bfed4741 core: improve conflict records storage scheme
Implement the https://github.com/neo-project/neo/issues/2907#issuecomment-1722506014
and port a part of https://github.com/neo-project/neo/pull/2913.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-10 17:34:27 +03:00
Roman Khimov
fce98a0af8
Merge pull request #3153 from nspcc-dev/fix-codecov
.github: upgrade coverage uploading action
2023-10-10 14:30:30 +03:00
Roman Khimov
2f747dd8d9
Merge pull request #3150 from nspcc-dev/drop-deprecated
Drop deprecated things
2023-10-10 14:29:47 +03:00
Roman Khimov
8fcf1eecfa
Merge pull request #3110 from nspcc-dev/fix-tests
Fix race caused by design of native Neo validators/committee cache
2023-10-10 14:29:28 +03:00
Anna Shaleva
bb9b8368a8 .github: upgrade coverage uploading action
Currently it's failing, but no token is required for public repos:
```
[2023-10-10T10:35:11.917Z] ['error'] There was an error running the uploader: Error uploading to https://codecov.io: Error: There was an error fetching the storage URL during POST: 404 - {'detail': ErrorDetail(string='Unable to locate build via Github Actions API. Please upload with the Codecov repository upload token to resolve issue.', code='not_found')}
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-10 13:53:20 +03:00
Roman Khimov
460362ab2e config: drop deprecated Protocol configurations
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-10-10 13:26:07 +03:00
Roman Khimov
9f7b19f886 config: drop implicit consensus config via UnlockWallet
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-10-10 13:26:07 +03:00
Roman Khimov
6865848ca7 config: drop deprecated P2P configuration
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-10-10 13:26:07 +03:00
Roman Khimov
de69560c7d config: drop deprecated address/port configurations
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-10-10 13:26:07 +03:00
Roman Khimov
a59afa8ea3 config: drop obsolete SecondsPerBlock protocol configuration
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-10-10 13:26:07 +03:00
Roman Khimov
eb995c8600 rpcclient: drop deprecated Notifications an Subscribe*
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-10-10 13:26:07 +03:00
Roman Khimov
413caac941 rpcclient: drop deprecated Client APIs
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-10-10 13:26:07 +03:00
Anna Shaleva
d9644204ee native: make newEpochNextValidators always contain non-empty value
If it's the end of epoch, then it contains the updated validators list recalculated
during the last block's PostPersist. If it's middle of the epoch, then it contains
previously calculated value (value for the previous completed epoch) that is equal
to the current nextValidators cache value.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-10 13:18:05 +03:00
Anna Shaleva
f78f915071 native: optimize NEO's committee/validators cache handling
Do not recalculate new committee/validators value in the start of every
subsequent epoch. Use values that was calculated in the PostPersist method
of the previously processed block in the end of the previous epoch.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-10 13:18:05 +03:00
Anna Shaleva
27dddb4d50 native: refactor argument of NEO's getCommitteeMembers function
No funcional changes, just refactoring. It doesn't need the whole cache,
only the set of committee keys with votes.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-10 13:18:05 +03:00
Anna Shaleva
794658b54c native: rename NEO's cached validators list to newEpochNextValidators
Adjust all comments, make the field name match its meaning.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-10 13:18:05 +03:00
Anna Shaleva
312534af7c native: don't recalculate validators every block
Recalculate them once per epoch. Consensus is aware of it and must
call CalculateNextValidators exactly when needed.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-10 13:18:05 +03:00
Anna Shaleva
07e1bc7cd7 core: rename (*Blockchain).GetValidators to ComputeNextBlockValidators
We have two similar blockchain APIs: GetNextBlockValidators and GetValidators.
It's hard to distinguish them, thus renaming it to match the meaning, so what
we have now is:

GetNextBlockValidators literally just returns the top of the committee that
was elected in the start of batch of CommitteeSize blocks batch. It doesn't
change its valie every block.

ComputeNextBlockValidators literally computes the list of validators based on
the most fresh committee members information got from the NeoToken's storage
and based on the latest register/unregister/vote events. The list returned by
this method may be updated every block.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-10 13:18:05 +03:00
Anna Shaleva
96449d803a native: rework native NEO next block validators cache
Blockchain passes his own pure unwrapped DAO to
(*Blockchain).ComputeNextBlockValidators which means that native
RW NEO cache structure stored inside this DAO can be modified by
anyone who uses exported ComputeNextBlockValidators Blockchain API,
and technically it's valid, and we should allow this, because it's
the only purpose of `validators` caching. However, at the same time
some RPC server is allowed to request a subsequent wrapped DAO for
some test invocation. It means that descendant wrapped DAO
eventually will request RW NEO cache and try to `Copy()`
the underlying's DAO cache which is in direct use of
ComputeNextBlockValidators. Here's the race:
ComputeNextBlockValidators called by Consensus service tries to
update cached `validators` value, and descendant wrapped DAO
created by the  RPC server tries to copy DAO's native cache and
read the cached `validators` value.

So the problem is that native cache not designated to handle
concurrent access between parent DAO layer and derived (wrapped)
DAO layer. I've carefully reviewed all the usages of native cache,
and turns out that the described situation is the only place where
parent DAO is used directly to modify its cache concurrently with
some descendant DAO that is trying to access the cache. All other
usages of native cache (not only NEO, but also all other native
contrcts) strictly rely on the hierarchical DAO structure and don't
try to perform these concurrent operations between DAO layers.
There's also persist operation, but it keeps cache RW lock taken,
so it doesn't have this problem as far. Thus, in this commit we rework
NEO's `validators` cache value so that it always contain the relevant
list for upper Blockchain's DAO and is updated every PostPersist (if
needed).

Note: we must be very careful extending our native cache in the
future, every usage of native cache must be checked against the
described problem.

Close #2989.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-10 13:18:05 +03:00
Roman Khimov
19c59c3a59
Merge pull request #3149 from nspcc-dev/fix-compiler-version-race
internal: avoid race access to config.Version by tests
2023-10-10 12:23:08 +03:00
Anna Shaleva
eeb439f548 internal: avoid race access to config.Version by tests
Network server constructor reads config.Version variable, and
testcli.DeployContract writes dummy config.Version which causes
race in tests. Avoid this race by moving config.Version initialisation
to a separate package and perform it inside test packages init().

Close #3011, close #3017.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-10 11:59:53 +03:00
Roman Khimov
cef70091f6
Merge pull request #3148 from fyfyrchik/fix-dump
storage: Use timeout for boltdb database opening
2023-10-09 12:40:07 +03:00
Evgenii Stratonikov
f1c6b9fe8f storage: Use timeout for boltdb database opening
To dump the DB, the service must be stopped.
If this is not the case `dump` command just hangs without any output,
which _may_ be unexpected from the ops POV.
Introduce a 1 second timeous, which is more than enough, given
that bbolt retries doing flock() every 50ms.

Signed-off-by: Evgenii Stratonikov <fyfyrchik@runbox.com>
2023-10-06 13:10:11 +03:00
Roman Khimov
b78bea17c0
Merge pull request #3147 from fyfyrchik/fix-big-uint64
compiler: Fix emitting big uint64 constants
2023-10-05 22:34:07 +03:00
Roman Khimov
32eb1e2606
Merge pull request #3146 from nspcc-dev/fix-link
zkpbinding: fix example link
2023-10-05 16:16:24 +03:00
Evgenii Stratonikov
96ee2e2b2d compiler: Fix emitting big uint64 constants
Currently we take int64 value from the Go parser and push it to the
stack. Using uint64 is not a common practice (usually we just use `int`),
but can be a problem while doing bit arithmetic and serializing numbers.

Signed-off-by: Evgenii Stratonikov <fyfyrchik@runbox.com>
2023-10-05 16:03:57 +03:00
Anna Shaleva
d27d2a8561 zkpbinding: fix example link
Should be a part of #3043.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 15:16:11 +03:00
Roman Khimov
91c928e8d3
Merge pull request #3043 from nspcc-dev/groth16-verify-compat
smartcontract, examples: add API for Groth16 Verifier contract building and examples
2023-10-05 13:58:21 +03:00
Anna Shaleva
fc6e87af2f *: update interop deps
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 13:46:56 +03:00
Anna Shaleva
a2d28272ef native: fix error message on unexpected BLS12-381 curve point
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 13:46:05 +03:00
Anna Shaleva
b5a75b1485 scripts: add zkp examples to dependencies updator
And ignore on dependency checks, we update all the examples at once
anyway, so may safely skip the check for zkp folder.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 13:46:05 +03:00
Anna Shaleva
1745b21142 *: upgrade gnark-crypto up to v0.12.0
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 13:46:05 +03:00
Anna Shaleva
e2abb5cb7c zkpbinding: update templates of go.sum and go.mod for Verifier contract
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 13:46:05 +03:00
Anna Shaleva
ca71bd51d3 zkpbinding: format formulae in Verifier template
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 13:46:05 +03:00
Anna Shaleva
b7e019e7ef native: ensure proper endianness is used for CryptoLib's field element multiplier
Field element multiplier must be provided in the LE form, confirmed by
cross-node invocation: https://github.com/nspcc-dev/neo-go/pull/3043#issuecomment-1733424840.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 13:46:05 +03:00
Anna Shaleva
8c46517522 zkpbinding: use proper field size for BLS12-381
It's not differ from BN254, but we'd better use the proper package.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 13:46:05 +03:00
Anna Shaleva
ff260a6a9b zkpbinding: allow to handle serialisation format of gnark >= v0.9.0
An upgrade from gnark v0.8.X to v0.9.0 changes serialization format of verifying/proving keys
and proofs. In neo-go zkpbinding package we have to support both at least for now, because
gnark@v0.9.0 requires minimum go 1.19.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 13:46:05 +03:00
Anna Shaleva
03951c94b0 examples: add production CRS generation instructions for ZKP examples
Add an example and instructions for production CRS generation to ZKP examples
with gnark >= v0.9.0.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 13:45:58 +03:00
Anna Shaleva
9e74fc5b47 zkp: add end-to-end Groth-16 proof generation/verification example
The example shows that the proover knows the solution of the cubic
equation: y = x^3 + x + 5. The example is constructed for BLS12-381
curve points using Groth-16 prooving algorithm. The example includes
everything that developer needs to start using ZKP on the NEO platform
with Go SDK:
1. The described cubic circuit implementation.
2. The off-chain proof generation with the help of gnark-crypto library.
3. Go verification contract generation and deployment with the help of
   NeoGo libraries.
4. The on-chain proof verification for various sets of input data.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 12:32:47 +03:00
Anna Shaleva
0a3260c22c examples: add compatibility example for Groth16 veification
Port the C# contract provided in the
https://github.com/neo-project/neo/issues/2647#issuecomment-1129849870 and
add an integration test for it. Part of the #3002.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-10-05 11:01:25 +03:00
Roman Khimov
4598f3d3c2
Merge pull request #3141 from nspcc-dev/limit-calculatenetworkfee-gas
Limit calculatenetworkfee GAS
2023-09-28 09:13:27 +03:00
Roman Khimov
49a44b0b9d rpcsrv: use stricter GAS limit for calculatenetworkfee
Valid transactions can't use more than MaxVerificationGAS for script execution
and this applies to the whole set of signers, so use this value by default
unless local instance configuration suggests something lower for generic
invocations.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-27 19:33:06 +03:00
Roman Khimov
fd2774ea91 rpcsrv: return core.ErrVerificationFailed from calculatenetworkfee
We can ignore core.ErrInvalidSignature (which means that the script has
executed, but returned false), but we shouldn't ignore other errors which
likely mean that the script is incorrect (or hits some resource limits).

Use neorpc.ErrInvalidSignature as a return to separate this case from
contract-based verification.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-27 19:30:23 +03:00
Roman Khimov
3628b824e1
Merge pull request #3140 from nspcc-dev/fix-wildcard-trusts-deserialization
smartcontract: fix wildcard trusts deserialization
2023-09-25 12:01:20 +03:00
Anna Shaleva
2581146a01 smartcontract: fix wildcard trusts deserialization
If manifest trusts presented as Null stackitem, then they should be
treated as wildcard, not as restricted.

It's not the same problem as described and fixed in
https://github.com/neo-project/neo/pull/2901 and
https://github.com/neo-project/neo/pull/2892, although these
two PRs are related.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-09-25 11:53:47 +03:00
Roman Khimov
f66abd020d
Merge pull request #3136 from nspcc-dev/fix-mainnet-neofs-config
config: fix mainnet neofs config
2023-09-19 18:40:19 +03:00
Roman Khimov
fda0e8364f config: fix mainnet neofs config
For some reason it got out of sync with the reality, Notary is enabled since
April there.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-19 18:30:33 +03:00
Roman Khimov
eb571a1356
Merge pull request #3129 from nspcc-dev/neofs-sdk-up
oracle/neofs: upgrade to SDK RC11
2023-09-13 11:13:53 +03:00
Roman Khimov
a0f9743515 oracle/neofs: avoid panic on failed neofs requests
2023-09-13T06:04:07.114Z        WARN        failed to perform oracle request        {"url": "neofs:BE2c15AbYnKdcsVh77LisCtjifoNEJUekANo1yhQ211X/FMDZvqUCqcduZa8HD6wJNsHWrJ6sqkgBveGuYuL38pvH", "error": "header: status: code = 3072 message = container not found"}
  panic: runtime error: invalid memory address or nil pointer dereference
  [signal SIGSEGV: segmentation violation code=0x1 addr=0x50 pc=0xde7c8f]
  goroutine 302 [running]:
  github.com/nspcc-dev/neofs-sdk-go/client.(*PayloadReader).close(0x0?, 0x0?)
          github.com/nspcc-dev/neofs-sdk-go@v1.0.0-rc.11/client/object_get.go:200 +0x2f
  github.com/nspcc-dev/neofs-sdk-go/client.(*PayloadReader).Close(0x0?)
          github.com/nspcc-dev/neofs-sdk-go@v1.0.0-rc.11/client/object_get.go:229 +0x1e
  github.com/nspcc-dev/neo-go/pkg/services/oracle/neofs.clientCloseWrapper.Close({{0x14b45f8?, 0x0?}, 0xc0010a1380?})
          github.com/nspcc-dev/neo-go/pkg/services/oracle/neofs/neofs.go:97 +0x3c
  github.com/nspcc-dev/neo-go/pkg/services/oracle.(*Oracle).processRequest(0xc000255800, 0xc001dfa210, {0xb2d?, 0xc001ad8000?})
          github.com/nspcc-dev/neo-go/pkg/services/oracle/request.go:168 +0xee7
  github.com/nspcc-dev/neo-go/pkg/services/oracle.(*Oracle).runRequestWorker(0xc000255800)
          github.com/nspcc-dev/neo-go/pkg/services/oracle/request.go:36 +0xe5
  created by github.com/nspcc-dev/neo-go/pkg/services/oracle.(*Oracle).start
          github.com/nspcc-dev/neo-go/pkg/services/oracle/oracle.go:216 +0xae

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-13 10:50:42 +03:00
Roman Khimov
0f57ad4a12 oracle/neofs: upgrade to SDK RC11
It requires explicit signers, and we have a problem with the old code:

  2023-09-12T18:42:00.063Z        WARN        failed to perform oracle request        {"url": "neofs:FMDZvqUCqcduZa8HD6wJNsHWrJ6sqkgBveGuYuL38pvH/5DCg4wUgWuWN3zsF4P4HdAzY2iKvXcrZ8QBLYGd1D1g2", "error": "failed to create client: incorrect signer: expected ECDSA_DETERMINISTIC_SHA256 scheme"}

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-13 10:50:42 +03:00
Roman Khimov
2d88ed9fe5
Merge pull request #3125 from nspcc-dev/rel-0.102.0
Release 0.102.0
2023-09-06 23:15:10 +03:00
Roman Khimov
31cc349725 ROADMAP: adjust wrt 0.102.0 release
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-06 22:08:26 +03:00
Roman Khimov
eb9735750c CHANGELOG: release 0.102.0
Co-Authored-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-06 22:08:26 +03:00
Roman Khimov
26c97a58ed
Merge pull request #3124 from nspcc-dev/hardforks
Set Basilisk hardforks for all networks
2023-09-06 16:54:29 +03:00
Roman Khimov
ee12520cbd config: set Basilisk fork height for NeoFS mainnet
Testnet doesn't need any (confirmed to have the same state for non-NEO
contracts) and can go with Basilisk from height 0.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-06 16:04:18 +03:00
Roman Khimov
a703e54563
Merge pull request #3122 from nspcc-dev/fix-neo-state-deserialization
state: always deserialize LastGasPerVote
2023-09-06 08:28:32 +03:00
Roman Khimov
9bdf66a5e0 state: always deserialize LastGasPerVote
It can be non-zero even if VoteTo is NULL. Fixes state diff with 3.6.0:

  block 41660: value mismatch for key +////xTrvgat3qG/w8hQoD/I4MgUz6rygA==: QQQhAS8hA7yiAAAhAA== vs QQQhAS8hA7yiAAAhB+POSWfBCAE=

Related to #2844.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-05 23:44:14 +03:00
Roman Khimov
98b946dcd3 config: set Basilisk hardfork heights for mainnet and testnet
Right from the https://github.com/neo-project/neo-node/pull/900

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-05 19:31:20 +03:00
Roman Khimov
c6850b49d9
Merge pull request #3121 from nspcc-dev/neotest-doc
neotest: improve doc based on #3120
2023-09-05 17:34:33 +03:00
Roman Khimov
4c015b30d5 neotest: improve doc based on #3120
We don't want anyone to have the same problem.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-05 15:20:00 +03:00
Roman Khimov
2f54f176fb
Merge pull request #3119 from nspcc-dev/neotest-doc
neotest: fix NewSingleSigner description, fix #3118
2023-09-05 13:04:48 +03:00
Roman Khimov
7cedcb9197 neotest: fix NewSingleSigner description, fix #3118
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-05 12:36:49 +03:00
Roman Khimov
e9d582f525
Merge pull request #2962 from nspcc-dev/notary-attr-upd
*: move NVB and Conflicts attributes out of extensions
2023-09-04 17:37:28 +03:00
Roman Khimov
fff7e91709 dao: simplify NewSimple()
We no longer need P2PSigExtension flag here, conflicts attribute is a part
of the normal protocol.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-04 16:56:59 +03:00
Anna Shaleva
f3c1283ac6 *: move NVB and Conflicts attributes out of extensions
They're a part of the regular protocol now.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-09-04 16:39:44 +03:00
Roman Khimov
a59fd50844
Merge pull request #3115 from nspcc-dev/3030-opcode-dumps
Add address and swap endianness to vm opcode dump for hashes
2023-09-04 12:05:35 +03:00
Tatiana Nesterenko
259cbc3356 vm: add address&swap endianness to opcode dump for hashes
If the parameter in the opcode dump is a 20-byte value, the converted values,
such as the address and the swapped endianness, have been added.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-09-04 08:41:22 +01:00
Roman Khimov
5180305240
Merge pull request #3117 from nspcc-dev/3070-unwrap-nothing
Add `unwrap.Nothing` function
2023-09-04 08:49:14 +03:00
Roman Khimov
cb1432233b
Merge pull request #3116 from nspcc-dev/2931-DBconfig-docs
Fix `DBConfiguration` description
2023-09-04 08:47:28 +03:00
Tatiana Nesterenko
59f72429b4 dbconfig: fix DBConfiguration description
The list of three supported types (`Type`) in the `DBConfiguration` struct
has been added.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-09-03 18:02:38 +01:00
Tatiana Nesterenko
acd821948f unwrap: add Nothing function
The `Nothing` function expects zero stack items and a successful invocation
(HALT state).

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-09-03 16:54:50 +01:00
Roman Khimov
0d30c834d5
Merge pull request #3098 from nspcc-dev/2951-getrawnotarypool
Implement `getrawnotaryrequest` and `getrawnotarytransaction` RPC extensions, close #2951.
2023-08-31 22:05:51 +03:00
Tatiana Nesterenko
7afa950eb7 docs: add getrawnotarypool, getrawnotarytransaction
Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-31 18:51:43 +01:00
Tatiana Nesterenko
d06f135792 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>
2023-08-31 18:51:43 +01:00
Tatiana Nesterenko
9e31e42bd9 rpcsrv: add getrawnotarypool, getrawnotarytransaction handlers
`getrawnotarytransaction` takes a transaction hash and attempts to find
the corresponding transaction in the notary requests mempool. It searches
through all the verified main and fallback transactions.
`getrawnotarypool` returns hashes of all the verified transactions,
including both main and fallback transactions.

Additionally add struct result.RawNotaryPool.

Close https://github.com/nspcc-dev/neo-go/issues/2951

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-31 18:51:43 +01:00
Tatiana Nesterenko
d285342d54 core: add function IterateVerifiedTransactions
IterateVerifiedTransactions iterates through verified transactions in
memory pool and invokes function cont. Where cont callback returns
whether we should continue with the traversal process.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-31 18:51:43 +01:00
Roman Khimov
1e6ef0c0e6
Merge pull request #3114 from omahs/patch-1
docs: fix typos
2023-08-31 18:04:14 +03:00
omahs
edf21e0b79 examples: fix typo
Signed-off-by: omahs <73983677+omahs@users.noreply.github.com>
2023-08-31 14:14:14 +02:00
omahs
e83916cef1 docs: fix typos
Signed-off-by: omahs <73983677+omahs@users.noreply.github.com>
2023-08-31 14:13:51 +02:00
Roman Khimov
abb35ad6fd
Merge pull request #3113 from nspcc-dev/prettify-dco
.github: prettify DCO check display name
2023-08-31 11:58:15 +03:00
Anna Shaleva
f330aaf313 .github: rename testing workflow file
Make it unified with the rest of workflow files.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-31 11:20:10 +03:00
Anna Shaleva
c80702cc4a .github: prettify DCO check display name
Extend the YAML scope and prettify the job check name.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-31 11:17:43 +03:00
Roman Khimov
5463a91edc
Merge pull request #3111 from nspcc-dev/rpcsrv-drop-unused-iface
rpcsrv: drop unused method from the Ledger interface
2023-08-30 10:55:23 +03:00
Roman Khimov
4a648692a2 rpcsrv: drop unused method from the Ledger interface
Inspired by #3110.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-08-29 22:33:26 +03:00
Roman Khimov
ad24aad9c0
Merge pull request #3108 from nspcc-dev/create-fallback-copy
notary: avoid changing pooled fallback transaction witnesses
2023-08-29 16:16:24 +03:00
Anna Shaleva
c63289a564 notary: avoid changing pooled fallback transaction witnesses
Forbid Notary service to change the fallback's witnesses in any way.
Fix the problem described in review comment:
https://github.com/nspcc-dev/neo-go/pull/3098#discussion_r1308336339.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-29 16:06:40 +03:00
Roman Khimov
2d4e1b598f
Merge pull request #3109 from nspcc-dev/reuse-org-dco-workflow
workflows: reuse org-wide DCO workflow
2023-08-29 15:08:51 +03:00
Roman Khimov
0b67fa9bca
Merge pull request #3107 from nspcc-dev/default-iter-items-conut
rpcsrv: enforce default config values on server creation if malformed value specified
2023-08-29 15:06:58 +03:00
Roman Khimov
1863b79c5c workflows: reuse org-wide DCO workflow
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-08-29 14:59:53 +03:00
Anna Shaleva
b89078c42a rpcsrv: set MaxNEP11Tokens to default if not specified
Do not use RPC configuration constructor for this, some external services
may skip this part.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-29 13:26:10 +03:00
Anna Shaleva
f5b0489d74 rpcsrv: set MaxFindStorageResultItems to default if not specified
Do not use RPC configuration constructor for this, some external services
may skip this part.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-29 13:26:10 +03:00
Anna Shaleva
dd7c762ff9 rpcsrv: set MaxFindResultItems to default if not specified
Do not use RPC configuration constructor for this, some external services
may skip this part.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-29 13:26:10 +03:00
Anna Shaleva
aeb7ee1021 rpcsrv: improve error formatting
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-29 13:26:05 +03:00
Anna Shaleva
97a57de82d rpcsrv: set MaxIteratorResultItems to default if not specified
Do not use RPC configuration constructor for this, some external services
may skip this part.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-29 13:19:39 +03:00
Roman Khimov
b4dff7b040
Merge pull request #3104 from nspcc-dev/hardforks-check
core: adjust hardfork enabling logic
2023-08-25 19:17:18 +03:00
Anna Shaleva
5d3938ae23 core: adjust hardfork enabling logic
Follow the logic described in https://github.com/neo-project/neo/pull/2886#issuecomment-1674745298
and port the https://github.com/neo-project/neo/pull/2886.

Close #3096.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-25 18:24:15 +03:00
Roman Khimov
7d75526c20
Merge pull request #3099 from nspcc-dev/findstorage
rpcsrv, rpcclient: support `findstorage`, `findstoragehistoric` and `getstoragehistoric` calls
2023-08-24 17:21:45 +03:00
Anna Shaleva
7b64b693bd rpcsrv: refactor findstoragehistoric handler to avoid DoS attack
Do not retrieve the whole set of storage items when trying to find
the ones from the specified start. Use DAO's Seek interface
implemented over MPT TrieStore to retrieve only the necessary items.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-24 17:15:59 +03:00
Anna Shaleva
c7d5ee0898 docs: refactor historical RPC calls documentation
1. Reorder paragraphs.
2. Extend common historical calls description.
2. Document `getstoragehistoric` and `findstoragehistoric` extensions.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-24 17:15:59 +03:00
Anna Shaleva
1fb0c96e2c rpcsrv, rpcclient: support getstoragehistoric call
Make it similar to `findstoragehistoric`.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-24 17:15:59 +03:00
Anna Shaleva
97d523ceed docs: fix typo
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-24 17:15:59 +03:00
Anna Shaleva
617c628c24 rpcsrv, rpcclient: support findstorage and findstoragehistoric
Close #3095 and add the corresponding historic extension.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-24 17:15:58 +03:00
Roman Khimov
87e4b6beaa
Merge pull request #3102 from nspcc-dev/upd-license
*: update LICENSE.md
2023-08-23 15:03:29 +03:00
Anna Shaleva
b9e957a05a *: update LICENSE.md
Adjust year, sort authors by contribution and fit authors in one line.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-23 14:26:45 +03:00
Anna Shaleva
124c3df2ff rpcsrv: rename testcases related to unsupported state
Testcase name should match the test purpose.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-22 19:54:07 +03:00
Roman Khimov
227b0c5480
Merge pull request #3041 from nspcc-dev/generic-decl
compiler: temporary disallow generics usages
2023-08-18 21:24:56 +03:00
Anna Shaleva
66a80017d3 docs: add note about type aliases and generics support
Part of #3023.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-18 17:01:45 +03:00
Roman Khimov
c5d9bf6e39
Merge pull request #3086 from nspcc-dev/ntf-strict-check
core: move strict notifications check under `HFBasilisk`
2023-08-18 16:55:20 +03:00
Anna Shaleva
bb2a99d451 smartcontract: disallow Null and non-utf8 String
Follow the https://github.com/neo-project/neo/pull/2810#discussion_r1295900728.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-18 16:41:33 +03:00
Anna Shaleva
ed2c4b0319 core: improve error checks in TestNotify
Ensure that the error returned from runtime.Notify is exactly the error
that was expected.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-18 16:41:33 +03:00
Anna Shaleva
2872c1c668 core: move contract notifications check under HFBasilisk
Follow the https://github.com/neo-project/neo/pull/2884.
A part of the https://github.com/neo-project/neo/pull/2810.
Fix failing tests along the way (a lot of them have invalid notifications
format which differs from the one declared in manifest).

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-18 16:40:20 +03:00
Anna Shaleva
35c3b65c8a compiler: disallow generic type decl
Need to be reverted and properly handled within the scope of #2376.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-18 16:02:40 +03:00
Anna Shaleva
380de580a7 compiler: disallow generic function parameter types
Need to be reverted and properly handled within the scope of #2376.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-18 16:02:40 +03:00
Anna Shaleva
1b1b454ce4 compiler: disallow generic method receiver
Either non-pointer or pointer, both cases are disallowed to be generic.
Need to be reverted and properly handled within the scope of #2376.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-18 16:02:39 +03:00
Anna Shaleva
415d44792a compiler: properly retrieve name of generic functions
Fix panic described in #3040. Ref. #2376.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-18 16:00:54 +03:00
Anna Shaleva
87aaaf1a67 core: rename TestManagement_DeployUpdateHardfork
So that hardfork name was explicitly present in the test name. We'll
have a set of similar tests later.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-18 12:02:43 +03:00
Anna Shaleva
60795a899f smartcontract: improve invalid notification error text
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-18 12:02:43 +03:00
Roman Khimov
5c6a111d00
Merge pull request #3063 from tatiana-nspcc/rpcsrv-errors
RPC: add error codes and response errors
2023-08-16 17:38:18 +03:00
Tatiana Nesterenko
90f1b0fd17 core: change text in ErrInvalidVerificationContract
No functional changes, just a refactoring.
Change error text to be able to use this error from external packages.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-16 14:16:14 +01:00
Tatiana Nesterenko
f3760c1a98 rpcsrv: return ErrUnknownSession and ErrUnknownIterator
Behaviour change.
`terminatesession` returns ErrUnknownSession in case of impossibility of finding session,
previously there was no-error response with `false` result.
`traverseIterator`returns ErrUnknownSession in case of impossibility of finding session,
previously there was no-error response with default result; `traverseIterator`returns ErrUnknownIterator,
there were no such errors before.
Accordingly to proposal:
https://github.com/neo-project/proposals/pull/156
Also adding description of `traverseIterator` in docs/rpc.md.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-16 14:16:14 +01:00
Tatiana Nesterenko
f557959c24 rpcsrv: return error on invalid proof from verifyProof
This change makes code incompatible with C# node,
because currently no error is returned on invalid proof.
According to proposal:
https://github.com/neo-project/proposals/pull/156
Also adding `verifyProof` descpiption in docs/rpc.md.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-16 14:00:24 +01:00
Tatiana Nesterenko
2598257628 core: rename ErrInvalidVerification and ErrInvalidInvocation
No functional changes, just a refactoring.
Use more specific and meaningful names to be able to use these errors from external packages.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-16 14:00:24 +01:00
Tatiana Nesterenko
1e6372e6d9 rpcsrv: return error on unknown storage item from getstorage
Follow the reference implementation, the behaviour was changed in
237ef7d057.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-16 14:00:24 +01:00
Tatiana Nesterenko
d3fe92de14 rpcsrv: remove default request HTTP codes from switch statement
No functional changes, just a refactoring.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-16 14:00:24 +01:00
Tatiana Nesterenko
3b29720298 neorpc: add deprecated error codes for C#-compatibility
While our server no longer uses these codes (-100, -400) they still can come
from C# servers and while we consider them deprecated we better at least have
some definition of them until C# implements our proposal:
https://github.com/neo-project/proposals/pull/156
Also adding description of deprecated RPC error codes in ROADMAP.md.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-16 13:59:39 +01:00
Tatiana Nesterenko
3178c8ff78 docs: add proposal regarding response error codes
According to proposal:
https://github.com/neo-project/proposals/pull/156

Close #2248

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-16 13:59:37 +01:00
Tatiana Nesterenko
31ceb568cb neorpc: add error codes and response errors
According to proposal:
https://github.com/neo-project/proposals/pull/156

Close #2248

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-16 13:59:33 +01:00
Tatiana Nesterenko
3abddc78c0 core: split ErrAlreadyExists into ErrAlreadyExists and ErrAlreadyInPool
ErrAlreadyExists is in blockchain and ErrAlreadyInPool is in mempool.

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
2023-08-16 12:36:56 +01:00
Roman Khimov
9fb154a376
Merge pull request #3074 from nspcc-dev/fix-debug-info
compiler: fix sequence point boundaries
2023-08-12 00:17:19 +03:00
Anna Shaleva
d1fe64470d compiler: fix sequence point boundaries
Thanks to @fyrchik, see the
https://github.com/neo-project/neo-devpack-dotnet/pull/154/files#diff-ebf53d00d5ba1f1197fedd2b8111fe9a8f44fb96699ef1314d54d05d5ceeb3f3R27

See also the standard:
https://github.com/neo-project/proposals/blob/master/nep-19.mediawiki#method.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-11 20:16:02 +03:00
Roman Khimov
4e61e8238a
Merge pull request #3087 from nspcc-dev/smart-binding
rpcbinding: export any unexported fields of structures/events
2023-08-11 18:11:47 +03:00
Anna Shaleva
16d1d1e5eb rpcbinding: check duplicating struct fields before binding generation
RPC binding config may be malformed or the source .go contract may contain
structures like this:
```
type Str struct {
    Field int
    field int
}
```
We need to recognise these cases and return error. otherwise the resulting
binding can't be compiled.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-11 17:48:54 +03:00
Anna Shaleva
b4c0fcfaad cli: move RPC bindings related testdata to a separate folder
It helps us to keep the index clean and ordered. When some new RPC binding
test should be added, we don't need to search for a suitable place for it.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-11 17:03:04 +03:00
Anna Shaleva
b2f84c83b3 rpcbinding: reuse upperFirst helper where possible
No functional changes.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-11 15:32:00 +03:00
Anna Shaleva
1356721862 rpcbinding: export any unexported fields of structures/events
Perform private -> public transformation at the last step of RPC binding
generation so that it works not only with NeoGo contracts, but with any
other contracts.

Close #3083.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-11 15:31:08 +03:00
Roman Khimov
11c0f13d06
Merge pull request #3080 from nspcc-dev/extend-int-prec
vm: increase BigInt parsing precision
2023-08-10 13:30:04 +03:00
Anna Shaleva
624f193f94 vm: move JNumbers parsing precision under HFBasilisk
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-10 13:14:16 +03:00
Anna Shaleva
d90608ddbf vm: increase BigInt parsing precision
Follow the https://github.com/neo-project/neo/pull/2883.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-10 13:14:16 +03:00
Roman Khimov
562293c74b
Merge pull request #3066 from nspcc-dev/abort-msg
vm, compiler: support `ASSERTMSG` and `ABORTMSG`
2023-08-10 13:11:41 +03:00
Anna Shaleva
3608314c15 .github: enable submodules sync for actions/checkout@v3
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-10 12:54:07 +03:00
Anna Shaleva
158d8e69a4 vm: update VM json tests path
It was changed way back in 5a11f4b4ca.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-10 12:54:07 +03:00
Anna Shaleva
5b12be2ac7 compiler: add test for util.AbortMsg and util.AssertMsg
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-10 12:54:07 +03:00
Anna Shaleva
de43b39c2a *: update interop deps
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-10 12:54:06 +03:00
Anna Shaleva
11bb733f1a interop: support ABORTMSG, ASSERT, ASSERTMSG opcodes
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-10 12:41:30 +03:00
Anna Shaleva
e7f77e052f vm: add ABORTMSG and ASSERTMSG opcodes
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-10 12:41:30 +03:00
Roman Khimov
2493400525
Merge pull request #3085 from nspcc-dev/fix-oracle-instance 2023-08-10 12:02:26 +03:00
Anna Shaleva
c39153756a rpcsrv: carefully store Oracle service
And simplify atomic service value stored by RPC server. Oracle service can
either be an untyped nil or be the proper non-nil *oracle.Oracle.
Otherwise `submitoracleresponse` RPC handler doesn't work properly.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-10 10:12:01 +03:00
Roman Khimov
25f61b45dd
Merge pull request #3056 from nspcc-dev/revert-script-check-removal
core: create hardfork for strict script check
2023-08-09 20:55:55 +03:00
Anna Shaleva
50ee241377 core: move strict script check on deploy under HF condition
Follow the https://github.com/neo-project/neo/pull/2881.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-09 18:32:30 +03:00
Anna Shaleva
bd937bc500 Revert "core: remove contract script check on deploy/update"
This reverts commit 762a8da76a.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-09 18:30:47 +03:00
Anna Shaleva
6c1240d023 cli: fix failing TestRunWithHistoricState
Broken by #3084.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-09 15:26:38 +03:00
Roman Khimov
5fc61be5f6
Merge pull request #3084 from nspcc-dev/wrkshp-upd
examples, config: minor adjustments for workshop
2023-08-08 22:54:20 +03:00
Anna Shaleva
4e6b1c4a38 examples: extend storage contract
Add method that returns iterator. It's needed for the workshop.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-08 18:30:22 +03:00
Anna Shaleva
b5f17215db config: enable session-based iterators on privnet
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-08 18:29:02 +03:00
Roman Khimov
afa4530c7d
Merge pull request #3078 from nspcc-dev/fix-failing-tests
Take care of master branch after 0.101.4 release
2023-08-02 10:53:07 +03:00
Anna Shaleva
e82fcb48c4 go.sum: update sums after 0.101.4 merge
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-02 10:35:22 +03:00
Anna Shaleva
50a77f3fae rpcclient: fix test after 0.101.4 merge
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-02 10:35:19 +03:00
Roman Khimov
7e867aefc4
Merge pull request #3077 from nspcc-dev/rel-0.101.4
Rel 0.101.4
2023-08-01 19:41:26 +03:00
Anna Shaleva
18c42f7993
Merge branch 'master' into rel-0.101.4
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 19:34:34 +03:00
Anna Shaleva
80fdb1c90c CHANGELOG: release 0.101.4
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 19:23:01 +03:00
Anna Shaleva
e2c6bbb6b1 rpcsrv: properly set content-type and CORS for all headers
Not only for successful ones. Close #3075.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:47:48 +03:00
Anna Shaleva
8d5a41de6e vm: allow parsing scientific JSON numbers
52-bit precision is not enough for our 256-bit VM, but this value
matches the reference implementation, see the
https://github.com/neo-project/neo/issues/2879.

MaxIntegerPrec will be increased (or even removed) as soon as the
ref. issue is resolved.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:46:56 +03:00
Anna Shaleva
6615cce81d rpcclient: adjust unwrapContract helper
There may be no such contract, then Null stackitem is expected on stack.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:46:12 +03:00
Anna Shaleva
c0abc61613 smartcontract: allow to pass nil as parameter to (*Invoker).Call
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:45:52 +03:00
Anna Shaleva
bf871760c6 core: do not use formatted error if not needed
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:44:48 +03:00
Anna Shaleva
96aa10bb80 neorpc: adjust the way SignerWithWitness is marshalled
Marshal account with `0x` prefix and add a test.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:44:43 +03:00
Anna Shaleva
8db997c58a neorpc: adjust SignerWithWitness scopes parsing
Ensure that Scopes can be properly parsed not only from the string
representation, but also from a single byte. transaction.Signer
is not affected (checked against the C# implementation), only
RPC-related signer scopes are allowed to be unmarshalled from byte.

Close #3059.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:44:37 +03:00
Anna Shaleva
e30e262e66 network: forbid Notary contract to be a sender of main transaction
This prevents the possible attack on notary request sender when
malicious partie is allowed to send notary request with main transaction
being someone else's fallback.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:44:24 +03:00
Anna Shaleva
ebe4c4ce2b cli: add test for incremental DB dump and restore
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:44:03 +03:00
Roman Khimov
b560475e67 server: allow to create incremental dumps
Anything not starting from 0 is incremental by definition.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-08-01 17:43:57 +03:00
Roman Khimov
4383832aa2 go.mod: upgrade bolt to v1.3.7
Refs. nspcc-dev/neofs-node#999, it fixes a number of other Windows-related
issues as well.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-08-01 17:43:30 +03:00
Anna Shaleva
6abf5f6388 cli: allow to provide network-specific node config file
Close #2978.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:41:03 +03:00
Anna Shaleva
d560395985 core: prevent direct access to Notary contract if not active
Otherwise it will cause panic, which isn't expected behaviour.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:30:11 +03:00
Anna Shaleva
2c984e2393 core: initialize natives cache wrt NativeActivations
If the contract was deployed then cache must be initialized after
in-memory data reset. If the contract isn't active yet, then no
cache will be initialized on deploy (i.e. on call to Initialize()
method by native Management).

Close #2984.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:30:05 +03:00
Anna Shaleva
d0718a680f core: add InitializeCache method to Contract interface
Make the contracts cache initialization unified. The order of cache
iniitialization is not important and Nottary contract is added to the
bc.contracts.Contracts wrt P2PSigExtensions setting, thus no functional
changes, just refactoring for future applications.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:30:01 +03:00
Anna Shaleva
97b93c6833 *: adjust Prometheus metrics initialisation on node start
Initialize Prometheus metrics on node start where appropriate and review
the usage of the following metrics:
```
anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ find | grep prometheus.go
./pkg/network/prometheus.go
./pkg/core/stateroot/prometheus.go
./pkg/core/prometheus.go
./pkg/services/rpcsrv/prometheus.go
./pkg/services/metrics/prometheus.go
```

Close #2970.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:29:36 +03:00
Roman Khimov
288dee8871 rpcclient: close subscriber channels on wsReader exit
The reader is about to exit and it will close legacy c.Notifications, but it
will leave subscription channels at the same time. This is wrong since these
channels will no longer receive any new events, game over.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-08-01 17:29:14 +03:00
Roman Khimov
08b273266b rpcclient: correctly handle request channel closure
wsReader() closes c.done first and then goes over the list of
c.respChannels. Technically this means that any of the two can be taken in
this select.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-08-01 17:29:08 +03:00
Anna Shaleva
ab64f7cfe4 docs: fix typo
Remove unnecessary word left after documentation refactoring.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:28:52 +03:00
Leonard Lyubich
6e990f39de cli/node: Fix deadlock produced by instant RPC service start
If `StartWhenSynchronized` is unset in config, `node` command runs RPC
service instantly. Previously there was a ground for deadlock. Command
started RPC server synchronously. According to server implementation, it
sends all internal failures to the parameterized error channel. Deadlock
occured because main routine didn't scan the channel.

Run `rpcsrv.Server.Start` in a separate go-routine in `startServer`.
This prevents potential deadlock caused by writing into unread channel.

Fixes #2896.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
2023-08-01 17:27:28 +03:00
Leonard Lyubich
465d3f43d2 services/rpcsrv: Wait for subscription process to complete when stopped
Previously RPC server shutdown procedure listened to the execution
channel and stopped at the first element that arrived in the queue. This
could lead to the following problems:
 * stopper could steal the execution result from subscriber
 * stopper didn't wait for other subscription actions to complete

Add dedicated channel to `Server` for subscription routine. Close the
channel on `handleSubEvents` return and wait for signal in `Shutdown`.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
2023-08-01 17:27:21 +03:00
Leonard Lyubich
f8227aa5f7 services/rpcsrv: Fix potential shutdown deadlock of RPC server
Previously RPC server could never be shut down completely due to
some start precondition failure (in particular, inability to serve HTTP
on any configured endpoint). The problem was caused by next facts:
 * start method ran subscription routine after HTTP init succeeded only
 * stop method blocked waiting for the subscription routine to return

Run `handleSubEvents` routine on fresh `Start` unconditionally. With
this change, `Shutdown` method won't produce deadlock since
`handleSubEvents` closes wait channel.

Refs #2896.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
2023-08-01 17:27:11 +03:00
Leonard Lyubich
758c455c7e services/rpcsrv: Test Server shutdown with failed precondition
There is an existing problem with RPC server shutdown freeze after start
failure due to some init actions (at least HTTP listen) described in
#2896.

Add dedicated unit test which checks that `Shutdown` returns within 5s
after `Start` method encounters internal problems.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
2023-08-01 17:27:03 +03:00
Anna Shaleva
c880873105 core: improve documentation to SetOracle/SetNotary
I've carefully checked the way how new service can be added to the
Blockchain instance or to be removed from it. Current implemention
of SetNotary and SetOracle methods doesn't contain dangerous code,
and native contracts have atomic values everywhere where service
is stored.

Current implementation of Notary, Oracle and StateRoot services'
reload/disabling/enabling on SIGUSR1 is safe and doesn't require
any adjustment.

This commit closes #2944, it's not a bug in the code, it's just
stale documentation.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:26:17 +03:00
Anna Shaleva
d5f964f181 config: do not allow negative validators count
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:22:39 +03:00
Anna Shaleva
6cd0f78649 config: do not allow zero numbers for validators/committee history
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:22:33 +03:00
Anna Shaleva
56b93d279e config: use uint32 for validators/committee members count
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:22:28 +03:00
Anna Shaleva
7028930bd6 network: do not use error channel to start network srv
It's obsolete thing, we have looger and it perfectly suits our needs.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:22:01 +03:00
Roman Khimov
eeab9c1b2e
Merge pull request #3076 from nspcc-dev/fix-content-type
rpcsrv: properly set content-type and CORS for all headers
2023-08-01 16:17:38 +03:00
Anna Shaleva
01a5816f04 rpcsrv: properly set content-type and CORS for all headers
Not only for successful ones. Close #3075.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 16:12:53 +03:00
Roman Khimov
03b9b4a4a1
Merge pull request #3073 from nspcc-dev/fix-sci-jnum
JSON scientific numbers kludge
2023-08-01 15:06:32 +03:00
Anna Shaleva
4be692193e vm: allow parsing scientific JSON numbers
52-bit precision is not enough for our 256-bit VM, but this value
matches the reference implementation, see the
https://github.com/neo-project/neo/issues/2879.

MaxIntegerPrec will be increased (or even removed) as soon as the
ref. issue is resolved.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-31 17:19:05 +03:00
Roman Khimov
3bbb21bf8f
Merge pull request #3072 from nspcc-dev/fix-contract-unwrap
rpcclient: adjust `unwrapContract` helper
2023-07-28 20:12:09 +03:00
Anna Shaleva
e57967b11c rpcclient: adjust unwrapContract helper
There may be no such contract, then Null stackitem is expected on stack.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-28 18:51:25 +03:00
Roman Khimov
081f9d3ac5
Merge pull request #3061 from nspcc-dev/check-onchain-conflicts
core: check the signers of on-chained conflicting transaction during new transaction verification
2023-07-21 22:36:21 +03:00
Anna Shaleva
ee4b8f883b core: check signers of on-chained conflict during new tx verification
During new transaction verification if there's an on-chain conflicting
transaction, we should check the signers of this conflicting transaction.
If the signers intersect with signers of the incoming transaction, then
the conflict is treated as valid and verification for new incoming
transaction should fail. Otherwise, the conflict is treated as the
malicious attack attempt and will not be taken into account;
verification for the new incoming transaction should continue.

This commint implements the scheme described at
https://github.com/neo-project/neo/pull/2818#issuecomment-1632972055,
thanks to @shargon for digging.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-21 17:27:47 +03:00
Roman Khimov
7a7d0a06ce
Merge pull request #3067 from nspcc-dev/allow-nil-arg
smartcontract: allow to pass nil as parameter to (*Invoker).Call
2023-07-21 14:51:10 +03:00
Anna Shaleva
0d17273476 core: fix formatted error on transaction verification
Witnesses are not yet created by the moment we return this error,
thus, it was always 0 as an actual number of witnesses in
ErrInvalidWitnessNum.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-21 13:50:20 +03:00
Anna Shaleva
0a2be89964 core: remove unused blockchain API
`(*Blockchain).HasTransaction` is one of the oldest methods in our
codebase, and currently it's completely unused. I also doubt that
this method works as expected because it returns `true` if transaction
in the mempool.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-21 13:37:02 +03:00
Anna Shaleva
c926d53869 smartcontract: allow to pass nil as parameter to (*Invoker).Call
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-21 13:19:25 +03:00
Roman Khimov
862c2e4ed3
Merge pull request #3060 from nspcc-dev/extend-rpc-signers
neorpc: adjust `SignerWithWitness` marshalling scheme
2023-07-20 17:27:23 +03:00
Roman Khimov
35ebdc1c91
Merge pull request #3065 from nspcc-dev/forbid-notary-sender
network: forbid Notary contract to be a sender of main transaction
2023-07-20 11:09:19 +03:00
Anna Shaleva
966111f4a8 network: forbid Notary contract to be a sender of main transaction
This prevents the possible attack on notary request sender when
malicious partie is allowed to send notary request with main transaction
being someone else's fallback.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-20 10:56:48 +03:00
Anna Shaleva
8253025c90 core: do not use formatted error if not needed
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-20 10:33:50 +03:00
Anna Shaleva
165525b7e9 neorpc: adjust the way SignerWithWitness is marshalled
Marshal account with `0x` prefix and add a test.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-20 10:33:50 +03:00
Anna Shaleva
9f69522ff5 neorpc: adjust SignerWithWitness scopes parsing
Ensure that Scopes can be properly parsed not only from the string
representation, but also from a single byte. transaction.Signer
is not affected (checked against the C# implementation), only
RPC-related signer scopes are allowed to be unmarshalled from byte.

Close #3059.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-20 10:33:48 +03:00
Anna Shaleva
e7a83cbef9
Merge pull request #3057 from nspcc-dev/upd-release-doc
docs: adjust release instructions
2023-07-11 18:32:03 +05:00
Anna Shaleva
8fcfa2c11a docs: adjust release instructions
Our assets will be automatically attached to the release after #3010.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-11 08:36:05 +03:00
Anna Shaleva
ee885bafdf
Merge pull request #3053 from nspcc-dev/rel-0.101.3
Release 0.101.3
2023-07-08 14:11:28 +05:00
Anna Shaleva
146775213a CHANGELOG: release 0.101.3
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-08 11:54:07 +03:00
Anna Shaleva
762a8da76a core: remove contract script check on deploy/update
This check is good and was present here since #1729, but it was
accidently removed from the reference implementation (see the
discussion in https://github.com/neo-project/neo/issues/2848). The
removal of this check from the C# node leaded to the T5 testnet state
diff since 1670095 heigh which causes inability to process new blocks
since 2272533 height (see #3049). This check was added back to the
C# node in https://github.com/neo-project/neo/pull/2849, but it is
planned to be the part of the upcoming 3.6.0 C# node release.

We need to keep our testnet healthy, thus, strict contract script
check will be temporary removed from the node code and is planned
to be added back to be a part of the next 3.6.0-compatible release.

Close #3049.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-08 11:49:31 +03:00
Anna Shaleva
f611a793a7
Merge pull request #3052 from nspcc-dev/remove-script-check
core: remove contract script check on deploy/update
2023-07-08 13:40:05 +05:00
Anna Shaleva
68ad542639
Merge pull request #3047 from nspcc-dev/incremental-dump-creation
server: allow to create incremental dumps
2023-07-06 16:15:35 +05:00
Anna Shaleva
48c8ae359f
Merge pull request #3055 from nspcc-dev/dependabot/go_modules/google.golang.org/grpc-1.53.0
build(deps): bump google.golang.org/grpc from 1.48.0 to 1.53.0
2023-07-06 16:14:07 +05:00
dependabot[bot]
ca80cfea2b
build(deps): bump google.golang.org/grpc from 1.48.0 to 1.53.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.48.0 to 1.53.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.48.0...v1.53.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-05 21:28:13 +00:00
Anna Shaleva
6fa4bcdc1d core: remove contract script check on deploy/update
This check is good and was present here since #1729, but it was
accidently removed from the reference implementation (see the
discussion in https://github.com/neo-project/neo/issues/2848). The
removal of this check from the C# node leaded to the T5 testnet state
diff since 1670095 heigh which causes inability to process new blocks
since 2272533 height (see #3049). This check was added back to the
C# node in https://github.com/neo-project/neo/pull/2849, but it is
planned to be the part of the upcoming 3.6.0 C# node release.

We need to keep our testnet healthy, thus, strict contract script
check will be temporary removed from the node code and is planned
to be added back to be a part of the next 3.6.0-compatible release.

Close #3049.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-04 14:17:04 +03:00
Anna Shaleva
bfe8867e63 cli: add test for incremental DB dump and restore
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-07-03 13:53:41 +03:00
Roman Khimov
abb58fb7de
Merge pull request #3048 from nspcc-dev/rel-0.101.2
Release 0.101.2
2023-06-29 13:34:06 +03:00
Roman Khimov
91b57745ac
Merge pull request #3046 from nspcc-dev/mainnet-state-fix
interop/contract: fix state rollbacks for nested contexts
2023-06-29 12:24:23 +03:00
Roman Khimov
e993003b46 CHANGELOG: release 0.101.2
Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-06-29 12:20:26 +03:00
Anna Shaleva
3bf8192f98 rpcclient: make Notary Actor follow the request creation doc
All Notary contract witnesses in incomplete transaction (both main
and fallback) may either have invocation scripts pushing dummy signature
on stack or be empty, both ways are OK. Notary actor keeps main tx's
Notary witness empty and keeps fallback tx's Notary witness filled
with dummy signature.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-06-29 12:04:40 +03:00
Anna Shaleva
60e6fe05a7 docs: improve Notary's till value documentation
Close #2986.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-06-29 12:03:51 +03:00
Roman Khimov
70aed34d77 interop/contract: fix state rollbacks for nested contexts
Our wrapping optimization relied on the caller context having a TRY block,
but each context (including internal calls!) has an exception handling stack
of its own, which means that for an invocation stack of

    entry
    A.someMethodFromEntry()   # this one has a TRY
    A.internalMethodViaCALL() # this one doesn't
    B.someMethod()

we get `HasTryBlock() == false` for `A.internalMethodViaCALL()` context, which
leads to missing wrapper and missing rollbacks if B is to THROW. What this
patch does instead is it checks for any context within contract boundaries.

Fixes #3045.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-06-29 11:58:12 +03:00
Roman Khimov
50c8805034 *: drop legacy addresses from examples
They can't even be used now because they'll fail the conversion.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-06-29 11:56:26 +03:00
Anna Shaleva
84b00d46aa rpc: emit Null in case of Any parameter with zero-len value
Otherwise it leads to the following error in the TestActor_CallWithNilParam:
```
=== RUN   TestActor_CallWithNilParam
    logger.go:130: 2023-04-03T15:58:27.672+0300	INFO	initial gas supply is not set or wrong, setting default value	{"InitialGASSupply": "52000000"}
    logger.go:130: 2023-04-03T15:58:27.672+0300	INFO	P2PNotaryRequestPayloadPool size is not set or wrong, setting default value	{"P2PNotaryRequestPayloadPoolSize": 1000}
    logger.go:130: 2023-04-03T15:58:27.672+0300	INFO	MaxBlockSize is not set or wrong, setting default value	{"MaxBlockSize": 262144}
    logger.go:130: 2023-04-03T15:58:27.672+0300	INFO	MaxBlockSystemFee is not set or wrong, setting default value	{"MaxBlockSystemFee": 900000000000}
    logger.go:130: 2023-04-03T15:58:27.672+0300	INFO	MaxTransactionsPerBlock is not set or wrong, using default value	{"MaxTransactionsPerBlock": 512}
    logger.go:130: 2023-04-03T15:58:27.672+0300	INFO	MaxValidUntilBlockIncrement is not set or wrong, using default value	{"MaxValidUntilBlockIncrement": 5760}
    logger.go:130: 2023-04-03T15:58:27.675+0300	INFO	no storage version found! creating genesis block
    logger.go:130: 2023-04-03T15:58:27.675+0300	INFO	ExtensiblePoolSize is not set or wrong, using default value	{"ExtensiblePoolSize": 20}
    logger.go:130: 2023-04-03T15:58:27.675+0300	INFO	SessionPoolSize is not set or wrong, setting default value	{"SessionPoolSize": 20}
    logger.go:130: 2023-04-03T15:58:27.675+0300	INFO	MaxWebSocketClients is not set or wrong, setting default value	{"MaxWebSocketClients": 64}
    logger.go:130: 2023-04-03T15:58:27.675+0300	INFO	starting rpc-server	{"endpoint": "localhost:0"}
    logger.go:130: 2023-04-03T15:58:27.677+0300	DEBUG	done processing headers	{"headerIndex": 1, "blockHeight": 0, "took": "436.313µs"}
    logger.go:130: 2023-04-03T15:58:27.679+0300	DEBUG	done processing headers	{"headerIndex": 2, "blockHeight": 1, "took": "272.891µs"}
    logger.go:130: 2023-04-03T15:58:27.680+0300	DEBUG	done processing headers	{"headerIndex": 3, "blockHeight": 2, "took": "276.949µs"}
    logger.go:130: 2023-04-03T15:58:27.681+0300	DEBUG	done processing headers	{"headerIndex": 4, "blockHeight": 3, "took": "286.028µs"}
    logger.go:130: 2023-04-03T15:58:27.681+0300	DEBUG	done processing headers	{"headerIndex": 5, "blockHeight": 4, "took": "268.673µs"}
    logger.go:130: 2023-04-03T15:58:27.681+0300	INFO	bad notification	{"contract": "565cff9508ebc75aadd7fe59f38dac610ab6093c", "event": "Transfer", "error": "parameter 0 type mismatch: Hash160 vs ByteString"}
    logger.go:130: 2023-04-03T15:58:27.682+0300	DEBUG	done processing headers	{"headerIndex": 6, "blockHeight": 5, "took": "380.988µs"}
    logger.go:130: 2023-04-03T15:58:27.683+0300	DEBUG	done processing headers	{"headerIndex": 7, "blockHeight": 6, "took": "273.543µs"}
    logger.go:130: 2023-04-03T15:58:27.683+0300	DEBUG	done processing headers	{"headerIndex": 8, "blockHeight": 7, "took": "275.163µs"}
    logger.go:130: 2023-04-03T15:58:27.684+0300	DEBUG	done processing headers	{"headerIndex": 9, "blockHeight": 8, "took": "259.578µs"}
    logger.go:130: 2023-04-03T15:58:27.685+0300	DEBUG	done processing headers	{"headerIndex": 10, "blockHeight": 9, "took": "266.882µs"}
    logger.go:130: 2023-04-03T15:58:27.686+0300	DEBUG	done processing headers	{"headerIndex": 11, "blockHeight": 10, "took": "295.3µs"}
    logger.go:130: 2023-04-03T15:58:27.687+0300	DEBUG	done processing headers	{"headerIndex": 12, "blockHeight": 11, "took": "295.568µs"}
    logger.go:130: 2023-04-03T15:58:27.688+0300	DEBUG	done processing headers	{"headerIndex": 13, "blockHeight": 12, "took": "258.197µs"}
    logger.go:130: 2023-04-03T15:58:27.689+0300	DEBUG	done processing headers	{"headerIndex": 14, "blockHeight": 13, "took": "261.602µs"}
    logger.go:130: 2023-04-03T15:58:27.689+0300	DEBUG	done processing headers	{"headerIndex": 15, "blockHeight": 14, "took": "268.922µs"}
    logger.go:130: 2023-04-03T15:58:27.690+0300	DEBUG	done processing headers	{"headerIndex": 16, "blockHeight": 15, "took": "276.176µs"}
    logger.go:130: 2023-04-03T15:58:27.691+0300	DEBUG	done processing headers	{"headerIndex": 17, "blockHeight": 16, "took": "256.068µs"}
    logger.go:130: 2023-04-03T15:58:27.692+0300	DEBUG	done processing headers	{"headerIndex": 18, "blockHeight": 17, "took": "262.303µs"}
    logger.go:130: 2023-04-03T15:58:27.692+0300	DEBUG	done processing headers	{"headerIndex": 19, "blockHeight": 18, "took": "265.087µs"}
    logger.go:130: 2023-04-03T15:58:27.693+0300	DEBUG	done processing headers	{"headerIndex": 20, "blockHeight": 19, "took": "260.758µs"}
    logger.go:130: 2023-04-03T15:58:27.694+0300	DEBUG	done processing headers	{"headerIndex": 21, "blockHeight": 20, "took": "263.482µs"}
    logger.go:130: 2023-04-03T15:58:27.694+0300	DEBUG	done processing headers	{"headerIndex": 22, "blockHeight": 21, "took": "327.812µs"}
    logger.go:130: 2023-04-03T15:58:27.696+0300	DEBUG	done processing headers	{"headerIndex": 23, "blockHeight": 22, "took": "284.104µs"}
    logger.go:130: 2023-04-03T15:58:27.697+0300	WARN	contract invocation failed	{"tx": "82279bfe9bada282ca0f8cb8e0bb124b921af36f00c69a518320322c6f4fef60", "block": 23, "error": "at instruction 0 (ABORT): ABORT"}
    logger.go:130: 2023-04-03T15:58:27.697+0300	DEBUG	processing rpc request	{"method": "getversion", "params": "[]"}
    logger.go:130: 2023-04-03T15:58:27.698+0300	DEBUG	processing rpc request	{"method": "invokefunction", "params": "[565cff9508ebc75aadd7fe59f38dac610ab6093c putValue  ]"}
    client_test.go:2562:
        	Error Trace:	/home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/services/rpcsrv/client_test.go:2562
        	Error:      	Should be true
        	Test:       	TestActor_CallWithNilParam
        	Messages:   	at instruction 6 (PACK): OPACK: invalid length
    logger.go:130: 2023-04-03T15:58:27.699+0300	INFO	shutting down RPC server	{"endpoint": "127.0.0.1:46005"}
    logger.go:130: 2023-04-03T15:58:27.700+0300	INFO	persisted to disk	{"blocks": 23, "keys": 1236, "headerHeight": 23, "blockHeight": 23, "took": "908.825µs"}
--- FAIL: TestActor_CallWithNilParam (0.03s)

FAIL
```

See also the ref. df534f6b0c/src/Neo/SmartContract/ContractParameter.cs (L141)
and the way how parameters are handled by ref. RPC server:
4b3a76e1b7/src/RpcServer/RpcServer.SmartContract.cs (L202)
and FromJSON implementation:
df534f6b0c/src/Neo/SmartContract/ContractParameter.cs (L70)
2023-06-29 11:51:40 +03:00
Roman Khimov
a30f098f73 server: allow to create incremental dumps
Anything not starting from 0 is incremental by definition.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-06-29 11:41:33 +03:00
Roman Khimov
20b19d4599 interop/contract: fix state rollbacks for nested contexts
Our wrapping optimization relied on the caller context having a TRY block,
but each context (including internal calls!) has an exception handling stack
of its own, which means that for an invocation stack of

    entry
    A.someMethodFromEntry()   # this one has a TRY
    A.internalMethodViaCALL() # this one doesn't
    B.someMethod()

we get `HasTryBlock() == false` for `A.internalMethodViaCALL()` context, which
leads to missing wrapper and missing rollbacks if B is to THROW. What this
patch does instead is it checks for any context within contract boundaries.

Fixes #3045.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-06-29 11:35:10 +03:00
Roman Khimov
9185820289
Merge pull request #3042 from nspcc-dev/allow-gt-equality-comparison 2023-06-15 22:38:20 +03:00
Anna Shaleva
31e2076810 native: move BLS12-381-related operations to a separate file
No functional changes, just refactoring.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-06-15 18:58:27 +03:00
Anna Shaleva
ea13fbe94a core: improve errors logging for bls12381-related operations
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-06-15 15:01:10 +03:00
Anna Shaleva
71bcb8bade native: allow to use EQUAL opcode for BLS12-381 points comparison
That's the way how C# node handles equality checks for stackitem.Interop types
for these points. Ref. https://github.com/nspcc-dev/neo-go/issues/3002#issuecomment-1591220501.

Along the way, add GT case for CryptoLib's bls12381Equal method. It should be there since #2940.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-06-15 15:00:27 +03:00
Roman Khimov
a2daad6ba6
Merge pull request #3037 from nspcc-dev/sdk-upd
oracle: update NeoFS SDK to 1.0.0-rc.9
2023-06-06 18:02:08 +03:00
Anna Shaleva
0d470edf21 oracle: make use of ReadCloser returned from NeoFS's getters
Close #3032.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-06-06 17:40:19 +03:00
Anna Shaleva
4b2fc32462 oracle: update NeoFS SDK to 1.0.0-rc.9
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-06-06 11:47:24 +03:00
Roman Khimov
b86975b061
Merge pull request #3036 from nspcc-dev/fix-rpcbinding
rpcbinding: call `scriptFor*` as method
2023-06-06 00:12:15 +03:00
Anna Shaleva
802a2b3879 rpcbinding: call scriptFor* as method
Should be a part of #3035, otherwise generated bindings are failed to
be compiled.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-06-05 18:31:34 +03:00
Roman Khimov
f96ccf2bfe
Merge pull request #3035 from nspcc-dev/fix-rpcbinding
rpcbinding: convert `scriptFor*` from function to method
2023-06-05 18:00:40 +03:00
Anna Shaleva
c7836ed6e7 rpcbinding: convert scriptFor* from function to method
Should be a part of #3012, otherwise generated bindings are failed to
be compiled.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-06-05 17:50:07 +03:00
Roman Khimov
805157b7a0
Merge pull request #3034 from nspcc-dev/update-bolt
go.mod: upgrade bolt to v1.3.7
2023-06-05 16:25:23 +03:00
Roman Khimov
67ce9de181 go.mod: upgrade bolt to v1.3.7
Refs. nspcc-dev/neofs-node#999, it fixes a number of other Windows-related
issues as well.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-06-05 14:59:08 +03:00
Roman Khimov
a0117042e8
Merge pull request #3012 from nspcc-dev/dynamic-rpc-hash
cli: allow dynamic RPC binding contract hash
2023-06-01 16:16:42 +03:00
Anna Shaleva
f97eaddfd1 cli: allow dynamic RPC binding contract hash
Close #3006 and make a light base for #3007.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-06-01 16:06:28 +03:00
Roman Khimov
50fad8455f
Merge pull request #3031 from nspcc-dev/conflicts-priority
mempool: adjust the rule of conflicting transaction ranking
2023-06-01 13:48:46 +03:00
Anna Shaleva
68b9ff1f17 mempool: adjust the rule of conflicting transaction ranking
Pay for all the conflicts if you'd like to went in. Close #3028.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-06-01 13:33:21 +03:00
Roman Khimov
772e723e8e
Merge pull request #3008 from nspcc-dev/event-gen
Close #2891.
2023-05-31 23:56:51 +03:00
Roman Khimov
9a15d2d781
Merge pull request #3029 from nspcc-dev/drop-legacy-addresses-from-examples
*: drop legacy addresses from examples
2023-05-31 18:36:34 +03:00
Roman Khimov
8beb3f4515 *: drop legacy addresses from examples
They can't even be used now because they'll fail the conversion.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-05-31 18:32:02 +03:00
Anna Shaleva
9f9cec53bd rpcbinding: provide links to types in comments
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
8ae4a1e957 rpcbinding: adjust comment of FromStackItem template methods
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
2ce1454ef5 cli: improve error message for binding template
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
44dfe8342d compiler: disallow named types redeclaration via contract config
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
865bd6c9cc compiler: compare emitted event params if --guess-eventtypes enabled
In this case emitted event parameters should match from invocation to
invocation. It's an error otherwise (and if the type is not Any).

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
6379bcc15a compiler: properly set extended type name for unnamed structs
After the struct was registered as "unnamed", it has the own unique name.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
0195aae824 cli: add test for --guessed-eventtypes RPC binding generator flag
Currently we have problems with unnamed structs used as a parameter for
notifications, because there's no one-to-one correspondence between
notification parameter and the list of extended types used by the whole
contract. Otherwise eventtypes guessing works OK.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
3e2755e66d smartcontract: add test for user-defined extended event types configuration
config_extended.yml contains an example of user-defined configuration
file with extended event types. User-defined event types are allowed
to be named and complicated, i.e. properly support extended types
notation.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
a0d991a500 rpcbinding: support map[any]any conversion for extended types
Unfortunately, without pre-set user extended types configuration for events
and without --guess-eventtypes flag set we are allowed to rely only on manifest
information about types. Manifest can't give us a lot of information, but we
still need to be able to generate RPC binding. Arrays and structs are correctly
handled by the current code, but maps always rely on the fact that map's value
type is set. It's not true in the described case, so make the maps type convertor
handle this situation in a similar way how arrays are handled.

Without this commit the following panic occurs on attempt to generate RPC binding:
```
    --- FAIL: TestAssistedRPCBindings/testdata/notifications (0.01s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x7f7c0e]

goroutine 190 [running]:
testing.tRunner.func1.2({0x109cb40, 0x1d58760})
	/usr/local/go/src/testing/testing.go:1396 +0x24e
testing.tRunner.func1()
	/usr/local/go/src/testing/testing.go:1399 +0x39f
panic({0x109cb40, 0x1d58760})
	/usr/local/go/src/runtime/panic.go:884 +0x212
github.com/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding.extendedTypeToGo({0x22, {0x0, 0x0}, {0x0, 0x0}, 0x0, 0x0, {0x0, 0x0, 0x0}}, ...)
	/home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding/binding.go:515 +0x36e
github.com/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding.scTypeToGo({0xc000206d92?, 0xc000206d80?}, 0x22, 0xc0005d70e0)
	/home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding/binding.go:643 +0x138
github.com/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding.scTemplateToRPC({{0xc00049bb07, 0x7}, 0xc0004c89c0, {0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, ...}, ...}, ...)
	/home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding/binding.go:686 +0xbc4
github.com/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding.Generate({{0xc00049bb07, 0x7}, 0xc0004c89c0, {0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, ...}, ...})
	/home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/smartcontract/rpcbinding/binding.go:421 +0x387
github.com/nspcc-dev/neo-go/cli/smartcontract.contractGenerateSomething(0xc00043e2c0, 0x137cd00)
	/home/anna/Documents/GitProjects/nspcc-dev/neo-go/cli/smartcontract/generate.go:99 +0x855
github.com/nspcc-dev/neo-go/cli/smartcontract.contractGenerateRPCWrapper(0xc00043e2c0?)
	/home/anna/Documents/GitProjects/nspcc-dev/neo-go/cli/smartcontract/generate.go:60 +0x25
github.com/urfave/cli.HandleAction({0x1048380?, 0x137c660?}, 0x13?)
	/home/anna/go/pkg/mod/github.com/urfave/cli@v1.22.5/app.go:524 +0x50
github.com/urfave/cli.Command.Run({{0x123539d, 0x13}, {0x0, 0x0}, {0x0, 0x0, 0x0}, {0x12577ad, 0x2a}, {0x127ad35, ...}, ...}, ...)
	/home/anna/go/pkg/mod/github.com/urfave/cli@v1.22.5/command.go:173 +0x65b
github.com/urfave/cli.(*App).RunAsSubcommand(0xc0001f4000, 0xc00043e000)
	/home/anna/go/pkg/mod/github.com/urfave/cli@v1.22.5/app.go:405 +0x91b
github.com/urfave/cli.Command.startApp({{0x12281e1, 0x8}, {0x0, 0x0}, {0x0, 0x0, 0x0}, {0x1254d8a, 0x28}, {0x0, ...}, ...}, ...)
	/home/anna/go/pkg/mod/github.com/urfave/cli@v1.22.5/command.go:372 +0x6e7
github.com/urfave/cli.Command.Run({{0x12281e1, 0x8}, {0x0, 0x0}, {0x0, 0x0, 0x0}, {0x1254d8a, 0x28}, {0x0, ...}, ...}, ...)
	/home/anna/go/pkg/mod/github.com/urfave/cli@v1.22.5/command.go:102 +0x825
github.com/urfave/cli.(*App).Run(0xc00024e000, {0xc0004f6420, 0xb, 0xb})
	/home/anna/go/pkg/mod/github.com/urfave/cli@v1.22.5/app.go:277 +0x8a7
github.com/nspcc-dev/neo-go/cli/smartcontract.TestAssistedRPCBindings.func1.1(0x9f8829?)
	/home/anna/Documents/GitProjects/nspcc-dev/neo-go/cli/smartcontract/generate_test.go:395 +0x5fc
testing.tRunner(0xc0006824e0, 0xc0004a3680)
	/usr/local/go/src/testing/testing.go:1446 +0x10b
created by testing.(*T).Run
	/usr/local/go/src/testing/testing.go:1493 +0x35f
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
37af2031bb rpcbinding: properly add imports for simple types of event parameters
There are two ways of doing this: first one is to emit all notifications
parameter data into rpcbindings configuration on compile time (event if
the parameter has a simple type), and the second one is to fetch parameter
type from the manifest on rpcbinding file generation if needed (we always
have manifest at this stage, thus it's not a problem to retrieve necessary
information). The latter case is chosen to reduce the bindings configuration
file size.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
19cc6c6369 compiler: store ready-to-use notification names in bindings config
Notification and its parameters may have any UTF8-compatible name
which is inappropriate for bindings configuration and for the resulting
RPC bindings file. This commit stores the prettified version of
notification's name and parameters that are ready to be used in the
resulting RPC binding without any changes.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
41938ffa78 smartcontract: drop standard events before RPC binging generation
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
2c36802e23 binding: fix comment to the extended type field
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:43 +03:00
Anna Shaleva
e2580187a1 cli: fetch extended evet types from contract config
The user should specify it via parameter's `extendedtype` field and
via upper-level `namedtypes` field of the contract configuration YAML.

Also, as we have proper event structure source, make the `--guess-eventtype`
compilation option and make event types guess optional.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:53:41 +03:00
Anna Shaleva
194639bb15 compiler: fix typo in the method description
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:52:41 +03:00
Anna Shaleva
044ae477ca smartconract: generate RPC binding wrappers for events
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-31 15:52:39 +03:00
Anna Shaleva
ae52b2c2fa rpcbinding: fix binding indentation
New rule for writing blocks of code to our template: new line before
the block starts and new line after the block ends. This rule is the
same as the one we use during manual typing.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-30 17:37:06 +03:00
Roman Khimov
871ee18981
Merge pull request #3024 from nspcc-dev/add-mp-test
mempool: add test for concurrent conflicting tx addition
2023-05-26 22:52:29 +03:00
Anna Shaleva
db812f7fa5 mempool: add test for concurrent conflicting tx addition
Ref. https://github.com/neo-project/neo/pull/2818#discussion_r1206658847.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-26 20:20:47 +03:00
Anna Shaleva
0f0f7b364f rpcbinding: use typed return err value in etTypeConverter
Otherwise the resulting code can't be compiled.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-25 16:41:23 +03:00
Anna Shaleva
8beb9f23c3 smartcontract: add comments to binding config fields
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-25 16:41:23 +03:00
Anna Shaleva
36af361c2b smartcontract: add FromStackItem wrapper for RPC bindings
Make it exported and reusable from the user's code.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-24 11:27:49 +03:00
Anna Shaleva
b5ec1271d5 .gitignore: do not ignore compiler testdata
cli's testdata folder stores contracts examples and expected compilation
output, thus doesn't need to be ignored.

*.out files are the bindings outputs only, do not ignore them as far.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-24 11:27:49 +03:00
Anna Shaleva
7a06cea885 cli: allow to rewrite expected test output
Don't perform it manually every time.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-24 11:27:48 +03:00
Roman Khimov
aca12b58c0
Merge pull request #3020 from nspcc-dev/loadnef-enh-2
cli: properly load specified method for `run` VM CLI command
2023-05-19 16:39:41 +03:00
Anna Shaleva
ddfbf7a434 cli: remove code duplication in test
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-19 13:26:56 +03:00
Anna Shaleva
2f4fb3a079 cli: fix error description for run VM CLI command
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-19 13:26:56 +03:00
Anna Shaleva
b6b80f3abf cli: properly handle run VM CLI command
Properly load the provided method using NEF and hash specified. It allows
to have NEF properly set in the VM context and handle CALLT instruction
correctly.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-19 13:26:56 +03:00
Anna Shaleva
35c3518b37 examples: fix owner's verification of Runtime example contract
`update` and `destroy` methods of the contract should check for owner
witness without checking the trigger (and that's the way how Verify
method works for this contract).

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-19 13:26:56 +03:00
Roman Khimov
7b86a54fc0
Merge pull request #3016 from nspcc-dev/emit-convertible
vm: allow to emit stackitem.Convertible
2023-05-17 21:06:21 +03:00
Anna Shaleva
fc6029d006 vm: allow to emit uint and uint64 as a part of array
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-17 19:29:42 +03:00
Roman Khimov
d463bad96f
Merge pull request #3013 from nspcc-dev/loadnef-enh
cli: autocomplete contract-related filenames for `compile` and `loadnef` commands
2023-05-17 15:05:00 +03:00
Anna Shaleva
aace790651 cli: guess manifest filename from nef for loadnef VM CLI command
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-17 13:09:31 +03:00
Anna Shaleva
ed2b59e077 cli: use cosigners separator for VM CLI commands where appropriate
Needed for further VM CLI commands improvement, we'll add another
positional args.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-17 13:09:31 +03:00
Anna Shaleva
a2449ae8ae cli: autocomplete output filenames for contract compile cmd
It's enough to specify the input file only to get the standard output:
```
$ neo-go contract compile -i ./1-print/1-print.go
$ neo-go contract compile -i ./1-print/
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-17 13:09:30 +03:00
Anna Shaleva
3dbb733324 cli: require contract config file for bindings generation
It's an error if config file isn't provided and bindings config needs
to be generated.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-17 13:00:39 +03:00
Anna Shaleva
15138b2004 vm: allow to emit convertible
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-17 12:47:31 +03:00
Anna Shaleva
8e085d3ca3 vm: allow to make stackitem from *Uint160 and *Uint256
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-17 11:16:32 +03:00
Roman Khimov
d493afc941
Merge pull request #3018 from nspcc-dev/upd-dbft
gomod: fetch dBFT update
2023-05-16 16:08:09 +03:00
Anna Shaleva
8599e25fc3 gomod: fetch dBFT update
Send PrepareRequest on timeout only: https://github.com/nspcc-dev/dbft/pull/75.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-16 16:03:34 +03:00
Roman Khimov
4afc71ab6d
Merge pull request #3014 from nspcc-dev/node-cfg
cli: allow to provide single node config file

Close #2978.
2023-05-16 14:42:38 +03:00
Anna Shaleva
4be9e4347a cli: allow to provide network-specific node config file
Close #2978.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-16 13:23:55 +03:00
Roman Khimov
abf3ef5af7
Merge pull request #3009 from nspcc-dev/new-version
network: add `neogo_version` metric, deprecate `serv_node_version`
2023-05-11 14:38:35 +03:00
Anna Shaleva
649b9ac7b0 network: add neogo_version metric, deprecate serv_node_version
Close #2999.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-11 13:48:38 +03:00
Roman Khimov
230f54c38a
Merge pull request #3010 from AnnaShaleva/AS/upload-release-asset
github: automatically attach binaries to the release
2023-05-10 22:32:29 +03:00
Anna Shaleva
778ddfb277 github: automatically attach binaries to the release
Close #3001.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-05-10 19:39:45 +03:00
Roman Khimov
b47a891b9e
Merge pull request #3004 from nspcc-dev/require-error-is
*: use require.ErrorIs instead of require.True(t, error.Is())
2023-05-04 18:14:36 +03:00
Roman Khimov
433275265f *: use require.ErrorIs instead of require.True(t, error.Is())
This is just a much better way to do the same thing. Inspired by
nspcc-dev/neofs-sdk-go#407.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-05-04 17:03:47 +03:00
Roman Khimov
8e6025fbc8
Merge pull request #3000 from nspcc-dev/conloss-error-for-wsclient
rpcclient: provide some exported error for disconnected WSClient
2023-05-03 16:42:12 +03:00
Roman Khimov
fcaa24f928 rpcclient: provide some exported error for disconnected WSClient
Regular Client doesn't care much about connections, because HTTP client's Do
method can reuse old ones or create additional ones on the fly. So one request
can fail and the next one easily succeed. WSClient is different, it works via
a single connection and if it breaks, it breaks forever for this
client. Callers will get some error on every request afterwards and it'd be
nice for this error to be the same so that API users could detect
disconnection this way too.

Related to nspcc-dev/neofs-node#2325.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-05-03 16:08:54 +03:00
Roman Khimov
8bd9a7d420
Merge pull request #2995 from nspcc-dev/neofs-sdk-update
NeoFS SDK update
2023-05-02 14:25:31 +03:00
Roman Khimov
cef7ac2510
Merge pull request #2997 from nspcc-dev/fix-Lint
github: use minimum supported go version for Linter job
2023-04-28 12:28:26 +03:00
Roman Khimov
a0aef0e92f
Merge pull request #2996 from nspcc-dev/fix-lint
core: add nolint comment for deprecated error format style
2023-04-28 12:27:10 +03:00
Anna Shaleva
98d29570d3 github: use minimum supported go version for Linter job
It should be this way because we can't provide some features golangci-lint
require us to do due to the need to support not only the latest Go version,
but also two versions below.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-28 12:17:08 +03:00
Anna Shaleva
9c0a45c65e core: add nolint comment for deprecated error format style
Should be a part of 67d4d891ef.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-28 12:13:21 +03:00
Roman Khimov
0a160ee93b *: use CompareAndSwap instead of CAS for atomics
go.uber.org/atomic deprecated CAS methods in version 1.10 (that introduced
CompareAndSwap), so we need to fix it.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-04-28 12:07:19 +03:00
Roman Khimov
2567c4c672 oracle: update NeoFS SDK to 1.0.0-rc.8
We were using _very_ old version, so there is a number of changes, including:
 * fix for unlimited reads
 * UTF-8 check for HTTP requests

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-04-27 21:29:59 +03:00
Roman Khimov
dcea3f6107
Merge pull request #2988 from nspcc-dev/client/close-blockers
rpcclient: close WSClient subscriber on overflow
2023-04-26 22:23:49 +03:00
Roman Khimov
1bd22adcb3
Merge pull request #2994 from nspcc-dev/fix-init-cache
core: rework natives cache initialization
2023-04-26 14:54:52 +03:00
Anna Shaleva
67d4d891ef core: prevent direct access to Notary contract if not active
Otherwise it will cause panic, which isn't expected behaviour.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-26 14:11:12 +03:00
Anna Shaleva
edb2d46d5b core: initialize natives cache wrt NativeActivations
If the contract was deployed then cache must be initialized after
in-memory data reset. If the contract isn't active yet, then no
cache will be initialized on deploy (i.e. on call to Initialize()
method by native Management).

Close #2984.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-26 13:57:45 +03:00
Anna Shaleva
33c971b0e4 core: add InitializeCache method to Contract interface
Make the contracts cache initialization unified. The order of cache
iniitialization is not important and Nottary contract is added to the
bc.contracts.Contracts wrt P2PSigExtensions setting, thus no functional
changes, just refactoring for future applications.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-26 12:57:48 +03:00
Roman Khimov
29b3df10b6
Merge pull request #2992 from nspcc-dev/init-metrics-on-start
*: adjust Prometheus metrics initialisation on node start
2023-04-25 16:27:38 +03:00
Anna Shaleva
e2782aef05 *: adjust Prometheus metrics initialisation on node start
Initialize Prometheus metrics on node start where appropriate and review
the usage of the following metrics:
```
anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ find | grep prometheus.go
./pkg/network/prometheus.go
./pkg/core/stateroot/prometheus.go
./pkg/core/prometheus.go
./pkg/services/rpcsrv/prometheus.go
./pkg/services/metrics/prometheus.go
```

Close #2970.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-25 16:25:18 +03:00
Roman Khimov
bbdfdc3099
Merge pull request #2991 from nspcc-dev/revert-mgmt-ids
Revert "native: make management compatible with C# node 3.5.0"
2023-04-25 12:42:01 +03:00
Roman Khimov
b1f9ba193b
Merge pull request #2990 from nspcc-dev/adj-notary-doc
docs: improve Notary's `till` value documentation
2023-04-25 12:40:33 +03:00
Anna Shaleva
3f2e0e5441 Revert "native: make management compatible with C# node 3.5.0"
This reverts commit 236e633ee4.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-25 12:22:11 +03:00
Anna Shaleva
6e8328415c docs: improve Notary's till value documentation
Close #2986.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-25 12:03:01 +03:00
Anna Shaleva
dab13a4e2d rpcclient: close WSClient subscriber on overflow
Close #2894.

It should be noted that the subscriber's channel is being removed from the
list of receivers and closed, but it is still *in the list of subscribers*
and no unsubscription is performed by WSClient. Which means that RPC server
keeps sending notifications to WSClient and WSClient keeps dropping them
(because there's no receiver for this subscription and it's OK, WSClient
can handle this and this behaviour is documented). However, it's still the
caller's duty to call Unsubscribe() method for this subscription.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-25 11:42:17 +03:00
Anna Shaleva
4a49bf5de4 rpcclient: introduce WSOptions for WSClient
Make a separate structure for WSClient configuration.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-25 11:42:15 +03:00
Roman Khimov
f0a5430b5b
Merge pull request #2985 from nspcc-dev/bugfix/interop-unused-import
interop/util: Drop unused import
2023-04-22 17:37:17 +03:00
Leonard Lyubich
d90626d556 interop/util: Drop unused import
Remove no longer used import left after corresponding code removal in
4671fbb3be.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
2023-04-22 16:36:49 +04:00
Roman Khimov
6bcdf32c31
Merge pull request #2981 from nspcc-dev/fix-ntr-actor
docs: adjust Notary request submission documentation
2023-04-20 16:29:56 +03:00
Roman Khimov
a8f05d9833
Merge pull request #2983 from nspcc-dev/upd-interops
*: update interop deps after #2892
2023-04-20 16:18:36 +03:00
Anna Shaleva
dd8218f87a *: update interop deps after #2892
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-20 16:11:57 +03:00
Roman Khimov
c50ab95164
Merge pull request #2892 from ZhangTao1596/optimize-vote-reward
Optimize vote reward data, see also neo-project/neo#2841.
2023-04-20 14:26:58 +03:00
ZhangTao1596
fb7fce0775 native: optimize vote reward data (fix #2844)
Signed-off-by: ZhangTao1596 <zhangtao@ngd.neo.org>
2023-04-20 17:41:14 +08:00
Roman Khimov
7b109586ca
Merge pull request #2980 from nspcc-dev/close-notification-chans-on-wsclient-disconnect
Close notification channels on wsclient disconnect
2023-04-19 18:11:36 +03:00
Anna Shaleva
77836ea1d0 rpcclient: make Notary Actor follow the request creation doc
All Notary contract witnesses in incomplete transaction (both main
and fallback) may either have invocation scripts pushing dummy signature
on stack or be empty, both ways are OK. Notary actor keeps main tx's
Notary witness empty and keeps fallback tx's Notary witness filled
with dummy signature.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-19 18:05:25 +03:00
Roman Khimov
6eaa76520f rpcclient: close subscriber channels on wsReader exit
The reader is about to exit and it will close legacy c.Notifications, but it
will leave subscription channels at the same time. This is wrong since these
channels will no longer receive any new events, game over.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-04-19 16:25:43 +03:00
Roman Khimov
45b353781f rpcclient: correctly handle request channel closure
wsReader() closes c.done first and then goes over the list of
c.respChannels. Technically this means that any of the two can be taken in
this select.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
2023-04-18 19:36:27 +03:00
Roman Khimov
7bc9b6e323
Merge pull request #2979 from nspcc-dev/fix-typo
docs: fix typo
2023-04-18 19:11:04 +03:00
Anna Shaleva
ef925b2c0b docs: fix typo
Remove unnecessary word left after documentation refactoring.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-18 18:59:46 +03:00
Roman Khimov
a4cc6da766
Merge pull request #2966 from nspcc-dev/bugfix/2896-rpc-shutdown-deadlock
rpc: Fix deadlock produced during server shutdown
2023-04-17 10:36:30 +03:00
Leonard Lyubich
e29c33e449 cli/node: Fix deadlock produced by instant RPC service start
If `StartWhenSynchronized` is unset in config, `node` command runs RPC
service instantly. Previously there was a ground for deadlock. Command
started RPC server synchronously. According to server implementation, it
sends all internal failures to the parameterized error channel. Deadlock
occured because main routine didn't scan the channel.

Run `rpcsrv.Server.Start` in a separate go-routine in `startServer`.
This prevents potential deadlock caused by writing into unread channel.

Fixes #2896.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
2023-04-17 10:42:50 +04:00
Leonard Lyubich
e126bcc462 services/rpcsrv: Wait for subscription process to complete when stopped
Previously RPC server shutdown procedure listened to the execution
channel and stopped at the first element that arrived in the queue. This
could lead to the following problems:
 * stopper could steal the execution result from subscriber
 * stopper didn't wait for other subscription actions to complete

Add dedicated channel to `Server` for subscription routine. Close the
channel on `handleSubEvents` return and wait for signal in `Shutdown`.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
2023-04-17 10:42:50 +04:00
Leonard Lyubich
a113940f0b services/rpcsrv: Fix potential shutdown deadlock of RPC server
Previously RPC server could never be shut down completely due to
some start precondition failure (in particular, inability to serve HTTP
on any configured endpoint). The problem was caused by next facts:
 * start method ran subscription routine after HTTP init succeeded only
 * stop method blocked waiting for the subscription routine to return

Run `handleSubEvents` routine on fresh `Start` unconditionally. With
this change, `Shutdown` method won't produce deadlock since
`handleSubEvents` closes wait channel.

Refs #2896.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
2023-04-17 10:42:50 +04:00
Leonard Lyubich
649877d8f3 services/rpcsrv: Test Server shutdown with failed precondition
There is an existing problem with RPC server shutdown freeze after start
failure due to some init actions (at least HTTP listen) described in
#2896.

Add dedicated unit test which checks that `Shutdown` returns within 5s
after `Start` method encounters internal problems.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
2023-04-17 10:42:49 +04:00
Roman Khimov
e0abe2b858
Merge pull request #2969 from nspcc-dev/mp-metrics
Split notarypool and mempool metrics. Also, do not use metrics for temporary pools
created during block/transaction verification.

Close #2950.
2023-04-14 15:43:37 +03:00
Roman Khimov
b9f95a820c
Merge pull request #2972 from nspcc-dev/dynamic-services
core: improve documentation of SetOracle/SetNotary
2023-04-13 20:59:52 +03:00
Anna Shaleva
3a71aafc43 core: distinguish notarypool/mempool metrics
Move them to the core/network packages, close #2950. The name of
mempool's unsorted transactions metrics has been changed along the
way to match the core's metrics naming convention.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-13 18:40:19 +03:00
Anna Shaleva
7bcc62d99c *: fix Prometheus metrics comment formatting
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-13 18:36:08 +03:00
Anna Shaleva
49cea72e41 core: improve documentation to SetOracle/SetNotary
I've carefully checked the way how new service can be added to the
Blockchain instance or to be removed from it. Current implemention
of SetNotary and SetOracle methods doesn't contain dangerous code,
and native contracts have atomic values everywhere where service
is stored.

Current implementation of Notary, Oracle and StateRoot services'
reload/disabling/enabling on SIGUSR1 is safe and doesn't require
any adjustment.

This commit closes #2944, it's not a bug in the code, it's just
stale documentation.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-13 18:29:58 +03:00
Roman Khimov
a875409055
Merge pull request #2968 from nspcc-dev/bad-cfg-panic
config: do not allow negative validators/committee count
2023-04-13 14:31:07 +03:00
Anna Shaleva
a74454aaca config: do not allow negative validators count
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-13 13:43:14 +03:00
Anna Shaleva
0c049f620f config: do not allow zero numbers for validators/committee history
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-13 13:42:41 +03:00
Anna Shaleva
8149d33fef config: use uint32 for validators/committee members count
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-13 13:42:40 +03:00
Roman Khimov
8f9d101eab
Merge pull request #2967 from nspcc-dev/rpcsrv-err
network: do not use error channel to start network srv
2023-04-13 13:27:48 +03:00
Anna Shaleva
55ab38ed81 network: do not use error channel to start network srv
It's obsolete thing, we have looger and it perfectly suits our needs.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-13 13:21:34 +03:00
Roman Khimov
37f7c9d9a7
Merge pull request #2965 from nspcc-dev/cli-ops
cli: extend `util` with `ops` command
2023-04-12 17:29:29 +03:00
Anna Shaleva
541da7e83b cli: add util ops command
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-12 17:12:18 +03:00
Roman Khimov
fdec8ea3f7
Merge pull request #2952 from nspcc-dev/find-backwards
core: add `Backwards` option to System.Storage.Find

Port neo-project/neo#2819.
2023-04-12 17:09:30 +03:00
Anna Shaleva
1962dd956c *: update interop deps
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-12 16:47:08 +03:00
Anna Shaleva
d5bea0ad4c core: add Backwards option for storage iterators
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-12 16:45:38 +03:00
Roman Khimov
4f827de5cd
Merge pull request #2819 from nspcc-dev/optimize-state-reset
core: some state reset oprimizations
2023-04-11 19:11:10 +03:00
Anna Shaleva
400620a9fb core: avoid squashing of data from different state reset stages
`cache` persisting operation is concurrent with the storage modifications
made by further state reset stages. We can't allow situation when data
from the next stage are leaking into the previous stage. State reset stages
must be atomic in turms of DB persisting, thus, use another `upperCache`
MemCached store to keep them apart.

Here are the results of mainnet's BoltDB reset from 1.1M to 6K:

This patch:
```
anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ ./bin/neo-go db reset -m --debug --height 600000
2023-04-11T16:15:25.783+0300	INFO	MaxBlockSize is not set or wrong, setting default value	{"MaxBlockSize": 262144}
2023-04-11T16:15:25.783+0300	INFO	MaxBlockSystemFee is not set or wrong, setting default value	{"MaxBlockSystemFee": 900000000000}
2023-04-11T16:15:25.783+0300	INFO	MaxTransactionsPerBlock is not set or wrong, using default value	{"MaxTransactionsPerBlock": 512}
2023-04-11T16:15:25.783+0300	INFO	MaxValidUntilBlockIncrement is not set or wrong, using default value	{"MaxValidUntilBlockIncrement": 5760}
2023-04-11T16:15:25.787+0300	INFO	restoring blockchain	{"version": "0.2.8"}
2023-04-11T16:15:25.906+0300	INFO	initializing state reset	{"target height": 600000}
2023-04-11T16:15:25.906+0300	DEBUG	trying to reset blocks, transactions and AERs
2023-04-11T16:15:57.031+0300	INFO	intermediate batch of removed blocks, transactions and AERs is collected	{"batch": 1, "took": "31.125057214s"}
2023-04-11T16:16:12.644+0300	DEBUG	intermediate batch of removed blocks, transactions and AERs is persisted	{"batch": 1, "took": "15.613156971s", "keys": 321895}
2023-04-11T16:16:13.895+0300	INFO	intermediate batch of removed blocks, transactions and AERs is collected	{"batch": 2, "took": "16.663444208s"}
2023-04-11T16:16:19.784+0300	INFO	last batch of removed blocks, transactions and AERs is collected	{"batch": 3, "took": "5.760308543s"}
2023-04-11T16:16:19.784+0300	INFO	blocks, transactions ans AERs are reset	{"took": "53.878632911s"}
2023-04-11T16:16:22.870+0300	DEBUG	intermediate batch of removed blocks, transactions and AERs is persisted	{"batch": 2, "took": "8.974838893s", "keys": 334823}
2023-04-11T16:16:22.870+0300	DEBUG	trying to reset contract storage items
2023-04-11T16:16:27.272+0300	DEBUG	last batch of removed blocks, transactions and AERs is persisted	{"batch": 3, "took": "7.487357441s", "keys": 208913}
2023-04-11T16:17:23.678+0300	INFO	intermediate batch of contract storage items and IDs is collected	{"batch": 1, "took": "1m0.80711106s"}
2023-04-11T16:18:00.769+0300	INFO	intermediate batch of contract storage items and IDs is collected	{"batch": 2, "took": "36.967660061s"}
2023-04-11T16:18:20.478+0300	DEBUG	intermediate batch of contract storage items is persisted	{"batch": 1, "took": "56.796257788s", "keys": 200000}
2023-04-11T16:18:54.115+0300	INFO	intermediate batch of contract storage items and IDs is collected	{"batch": 3, "took": "33.637412437s"}
2023-04-11T16:19:18.844+0300	DEBUG	intermediate batch of contract storage items is persisted	{"batch": 2, "took": "1m18.0737668s", "keys": 200000}
2023-04-11T16:19:27.650+0300	INFO	last batch of contract storage items is collected	{"batch": 4, "took": "8.806264019s"}
2023-04-11T16:19:27.650+0300	INFO	contract storage items are reset	{"took": "3m4.780232077s", "keys": 656944}
2023-04-11T16:20:15.660+0300	DEBUG	intermediate batch of contract storage items is persisted	{"batch": 3, "took": "1m21.544386403s", "keys": 200000}
2023-04-11T16:20:15.660+0300	DEBUG	trying to reset headers information
2023-04-11T16:20:16.385+0300	INFO	headers information is reset	{"took": "725.174932ms"}
2023-04-11T16:20:19.586+0300	DEBUG	last batch of contract storage items and IDs is persisted	{"batch": 4, "took": "51.936278608s", "keys": 56945}
2023-04-11T16:20:19.587+0300	DEBUG	trying to reset state root information and NEP transfers
2023-04-11T16:20:35.845+0300	INFO	state root information and NEP transfers are reset	{"took": "16.25852114s"}
2023-04-11T16:21:10.000+0300	DEBUG	headers information is persisted	{"took": "53.613638429s", "keys": 528438}
2023-04-11T16:21:10.003+0300	DEBUG	trying to remove stale storage items
2023-04-11T16:21:18.108+0300	INFO	stale storage items are reset	{"took": "8.105140658s", "keys": 1350176}
2023-04-11T16:21:18.108+0300	DEBUG	trying to remove state reset point
2023-04-11T16:21:18.108+0300	INFO	state reset point is removed	{"took": "8.554µs"}
2023-04-11T16:21:20.151+0300	DEBUG	state root information and NEP transfers are persisted	{"took": "44.305707049s", "keys": 602578}
2023-04-11T16:21:20.212+0300	INFO	state reset point information is persisted	{"took": "2.103764633s", "keys": 2}
2023-04-11T16:21:20.213+0300	INFO	reset finished successfully	{"took": "5m54.306861367s"}
```

The previous commit:
```
anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ ./bin/neo-go db reset -m --debug --height 600000
2023-04-11T16:24:04.256+0300	INFO	MaxBlockSize is not set or wrong, setting default value	{"MaxBlockSize": 262144}
2023-04-11T16:24:04.256+0300	INFO	MaxBlockSystemFee is not set or wrong, setting default value	{"MaxBlockSystemFee": 900000000000}
2023-04-11T16:24:04.256+0300	INFO	MaxTransactionsPerBlock is not set or wrong, using default value	{"MaxTransactionsPerBlock": 512}
2023-04-11T16:24:04.256+0300	INFO	MaxValidUntilBlockIncrement is not set or wrong, using default value	{"MaxValidUntilBlockIncrement": 5760}
2023-04-11T16:24:04.261+0300	INFO	restoring blockchain	{"version": "0.2.8"}
2023-04-11T16:24:04.368+0300	INFO	initializing state reset	{"target height": 600000}
2023-04-11T16:24:04.368+0300	DEBUG	trying to reset blocks, transactions and AERs
2023-04-11T16:24:30.363+0300	INFO	intermediate batch of removed blocks, transactions and AERs is collected	{"batch": 1, "took": "25.995261037s"}
2023-04-11T16:24:44.947+0300	DEBUG	intermediate batch of removed blocks, transactions and AERs is persisted	{"batch": 1, "took": "14.584447338s", "keys": 321897}
2023-04-11T16:24:45.791+0300	INFO	intermediate batch of removed blocks, transactions and AERs is collected	{"batch": 2, "took": "15.428492824s"}
2023-04-11T16:24:51.252+0300	INFO	last batch of removed blocks, transactions and AERs is collected	{"batch": 3, "took": "5.460662766s"}
2023-04-11T16:24:51.252+0300	INFO	blocks, transactions ans AERs are reset	{"took": "46.884558096s"}
2023-04-11T16:24:55.399+0300	DEBUG	intermediate batch of removed blocks, transactions and AERs is persisted	{"batch": 2, "took": "9.607820004s", "keys": 334821}
2023-04-11T16:24:55.399+0300	DEBUG	trying to reset contract storage items
2023-04-11T16:24:59.981+0300	DEBUG	last batch of removed blocks, transactions and AERs is persisted	{"batch": 3, "took": "8.728713255s", "keys": 208913}
2023-04-11T16:25:50.827+0300	INFO	intermediate batch of contract storage items and IDs is collected	{"batch": 1, "took": "55.426411416s"}
2023-04-11T16:26:28.734+0300	INFO	intermediate batch of contract storage items and IDs is collected	{"batch": 2, "took": "37.902647706s"}
2023-04-11T16:26:53.960+0300	DEBUG	intermediate batch of contract storage items is persisted	{"batch": 1, "took": "1m3.129453265s", "keys": 200001}
2023-04-11T16:27:27.645+0300	INFO	intermediate batch of contract storage items and IDs is collected	{"batch": 3, "took": "33.685283662s"}
2023-04-11T16:27:52.173+0300	DEBUG	intermediate batch of contract storage items is persisted	{"batch": 2, "took": "1m23.438465575s", "keys": 199999}
2023-04-11T16:28:00.995+0300	INFO	last batch of contract storage items is collected	{"batch": 4, "took": "8.821990443s"}
2023-04-11T16:28:00.995+0300	INFO	contract storage items are reset	{"took": "3m5.595950958s", "keys": 656944}
2023-04-11T16:28:49.164+0300	DEBUG	intermediate batch of contract storage items is persisted	{"batch": 3, "took": "1m21.518344712s", "keys": 200000}
2023-04-11T16:28:49.164+0300	DEBUG	trying to reset headers information
2023-04-11T16:28:49.936+0300	INFO	headers information is reset	{"took": "772.36435ms"}
2023-04-11T16:28:53.122+0300	DEBUG	last batch of contract storage items and IDs is persisted	{"batch": 4, "took": "52.126928092s", "keys": 56945}
2023-04-11T16:28:53.122+0300	DEBUG	trying to reset state root information and NEP transfers
2023-04-11T16:29:09.332+0300	INFO	state root information and NEP transfers are reset	{"took": "16.20921699s"}
2023-04-11T16:29:46.264+0300	DEBUG	headers information is persisted	{"took": "56.326715249s", "keys": 528438}
2023-04-11T16:29:46.267+0300	DEBUG	trying to remove stale storage items
2023-04-11T16:29:53.986+0300	INFO	stale storage items are reset	{"took": "7.718950145s", "keys": 1350176}
2023-04-11T16:29:53.986+0300	DEBUG	trying to remove state reset point
2023-04-11T16:29:53.986+0300	INFO	state reset point is removed	{"took": "6.013µs"}
2023-04-11T16:29:55.899+0300	DEBUG	state root information and NEP transfers are persisted	{"took": "46.567302762s", "keys": 602578}
2023-04-11T16:29:55.929+0300	INFO	state reset point information is persisted	{"took": "1.942392208s", "keys": 2}
2023-04-11T16:29:55.929+0300	INFO	reset finished successfully	{"took": "5m51.561573137s"}
```

Master:
```
anna@kiwi:~/Documents/GitProjects/nspcc-dev/neo-go$ ./bin/neo-go db reset -m --debug --height 600000
2023-04-11T16:34:12.410+0300	INFO	MaxBlockSize is not set or wrong, setting default value	{"MaxBlockSize": 262144}
2023-04-11T16:34:12.410+0300	INFO	MaxBlockSystemFee is not set or wrong, setting default value	{"MaxBlockSystemFee": 900000000000}
2023-04-11T16:34:12.410+0300	INFO	MaxTransactionsPerBlock is not set or wrong, using default value	{"MaxTransactionsPerBlock": 512}
2023-04-11T16:34:12.410+0300	INFO	MaxValidUntilBlockIncrement is not set or wrong, using default value	{"MaxValidUntilBlockIncrement": 5760}
2023-04-11T16:34:12.413+0300	INFO	restoring blockchain	{"version": "0.2.8"}
2023-04-11T16:34:12.495+0300	INFO	initialize state reset	{"target height": 600000}
2023-04-11T16:34:12.513+0300	INFO	trying to reset blocks, transactions and AERs
2023-04-11T16:35:03.582+0300	INFO	intermediate batch of removed blocks, transactions and AERs is persisted	{"batches persisted": 1, "took": "51.087226195s", "keys": 321895}
2023-04-11T16:35:31.302+0300	INFO	intermediate batch of removed blocks, transactions and AERs is persisted	{"batches persisted": 2, "took": "27.719871393s", "keys": 334823}
2023-04-11T16:35:41.309+0300	INFO	last batch of removed blocks, transactions and AERs is persisted	{"batches persisted": 3, "took": "10.007017388s", "keys": 208913}
2023-04-11T16:35:41.309+0300	INFO	blocks, transactions ans AERs are reset	{"took": "1m28.814245057s", "overall persisted keys": 865631}
2023-04-11T16:35:41.309+0300	INFO	trying to reset contract storage items
2023-04-11T16:37:38.315+0300	INFO	intermediate batch of contract storage items and IDs is persisted	{"batch": 1, "took": "1m57.00650253s", "keys": 200000}
2023-04-11T16:39:29.704+0300	INFO	intermediate batch of contract storage items and IDs is persisted	{"batch": 2, "took": "1m51.385224725s", "keys": 200000}
2023-04-11T16:41:14.991+0300	INFO	intermediate batch of contract storage items and IDs is persisted	{"batch": 3, "took": "1m45.287483794s", "keys": 200000}
2023-04-11T16:41:31.667+0300	INFO	last batch of contract storage items and IDs is persisted	{"batch": 4, "took": "16.675347478s", "keys": 56945}
2023-04-11T16:41:31.667+0300	INFO	contract storage items and IDs are reset	{"took": "5m50.357775401s", "keys": 656944}
2023-04-11T16:41:31.667+0300	INFO	trying to reset headers information
2023-04-11T16:42:16.779+0300	INFO	headers information is reset	{"took": "45.111354262s", "keys": 528438}
2023-04-11T16:42:16.784+0300	INFO	trying to reset state root information and NEP transfers
2023-04-11T16:42:35.778+0300	INFO	state root information and NEP transfers are reset	{"took": "18.99373117s", "keys": 602578}
2023-04-11T16:42:35.781+0300	INFO	trying to remove stale storage items
2023-04-11T16:42:43.884+0300	INFO	stale storage items are reset	{"took": "8.103929306s", "keys": 1350176}
2023-04-11T16:42:43.885+0300	INFO	trying to remove state reset point
2023-04-11T16:42:43.926+0300	INFO	stale reset point is removed	{"took": "41.858883ms", "keys": 2}
2023-04-11T16:42:43.932+0300	INFO	reset finished successfully	{"took": "8m31.437493325s"}
```

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-11 18:49:09 +03:00
Anna Shaleva
cb0f786b28 core: move batch persist to a separate routine
Resetting mainnet from 2512046 blocks (full logs are attached
to https://github.com/nspcc-dev/neo-go/pull/2813#issuecomment-1324115555).

--------
LevelDB |
------------------------
  to  |  old   |   new  |
------|--------|--------|
  1   | 5m11s  | 4m50s  |
------|--------|--------|
  1M  | 10m40s | 9m40s  |
------|--------|--------|
 2.5M | 17m38s | 17m36s |
------------------------

--------
BoltDB  |
------------------------
  to  |  old   |   new  |
------|--------|--------|
  1   |  8m3s  | 5m51s  |
------|--------|--------|
  1M  | 20m30s | 13m2s  |
------|--------|--------|
 2.5M | 31m26s | 18m47s |
------------------------

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-11 16:58:11 +03:00
Anna Shaleva
e3747b1d57 core: change log level of reset stages notifications
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-11 16:58:03 +03:00
Anna Shaleva
41caeed5c0 core: fix state reset log message
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-11 16:57:56 +03:00
Roman Khimov
5322a3535b
Merge pull request #2940 from nspcc-dev/groth16
core: add BLS12_381 interops
2023-04-10 10:20:17 +03:00
Anna Shaleva
66b82d0a7d *: update interop dependency 2023-04-05 15:54:36 +03:00
Anna Shaleva
68cb07999b scripts: adjust dependency updator
We don't need these `--compat` flags anymore since 1.16 support is dropped.
2023-04-05 15:49:17 +03:00
Anna Shaleva
69102a6aa3 interop: add groth16 interop API 2023-04-05 15:37:50 +03:00
Anna Shaleva
115ec4d8dd core: add BLS12_381 interops 2023-04-05 15:37:50 +03:00
532 changed files with 29259 additions and 9643 deletions

View file

@ -16,7 +16,7 @@
"deployed": false "deployed": false
}, },
"lock": false, "lock": false,
"isdefault": false "isDefault": false
}, },
{ {
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq", "address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
@ -41,7 +41,7 @@
"deployed": false "deployed": false
}, },
"lock": false, "lock": false,
"isdefault": false "isDefault": false
} }
], ],
"scrypt": { "scrypt": {
@ -52,4 +52,4 @@
"extra": { "extra": {
"Tokens": null "Tokens": null
} }
} }

View file

@ -16,7 +16,7 @@
"deployed": false "deployed": false
}, },
"lock": false, "lock": false,
"isdefault": false "isDefault": false
}, },
{ {
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq", "address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
@ -41,7 +41,7 @@
"deployed": false "deployed": false
}, },
"lock": false, "lock": false,
"isdefault": false "isDefault": false
}, },
{ {
"address": "NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP", "address": "NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP",
@ -58,7 +58,7 @@
"deployed": false "deployed": false
}, },
"lock": false, "lock": false,
"isdefault": false "isDefault": false
} }
], ],
"scrypt": { "scrypt": {
@ -69,4 +69,4 @@
"extra": { "extra": {
"Tokens": null "Tokens": null
} }
} }

View file

@ -16,7 +16,7 @@
"deployed": false "deployed": false
}, },
"lock": false, "lock": false,
"isdefault": false "isDefault": false
}, },
{ {
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq", "address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
@ -41,7 +41,7 @@
"deployed": false "deployed": false
}, },
"lock": false, "lock": false,
"isdefault": false "isDefault": false
} }
], ],
"scrypt": { "scrypt": {
@ -52,4 +52,4 @@
"extra": { "extra": {
"Tokens": null "Tokens": null
} }
} }

View file

@ -16,7 +16,7 @@
"deployed": false "deployed": false
}, },
"lock": false, "lock": false,
"isdefault": false "isDefault": false
}, },
{ {
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq", "address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
@ -41,7 +41,7 @@
"deployed": false "deployed": false
}, },
"lock": false, "lock": false,
"isdefault": false "isDefault": false
} }
], ],
"scrypt": { "scrypt": {
@ -52,4 +52,4 @@
"extra": { "extra": {
"Tokens": null "Tokens": null
} }
} }

View file

@ -16,7 +16,7 @@
"deployed": false "deployed": false
}, },
"lock": false, "lock": false,
"isdefault": false "isDefault": false
}, },
{ {
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq", "address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
@ -41,7 +41,7 @@
"deployed": false "deployed": false
}, },
"lock": false, "lock": false,
"isdefault": false "isDefault": false
} }
], ],
"scrypt": { "scrypt": {
@ -52,4 +52,4 @@
"extra": { "extra": {
"Tokens": null "Tokens": null
} }
} }

2
.github/CODEOWNERS vendored
View file

@ -1 +1 @@
* @AnnaShaleva @roman-khimov @fyrchik * @AnnaShaleva @roman-khimov

View file

@ -37,29 +37,23 @@ jobs:
runs-on: ${{matrix.os.name}} runs-on: ${{matrix.os.name}}
strategy: strategy:
matrix: matrix:
os: [{ name: ubuntu-20.04, bin-name: linux }, { name: windows-2022, bin-name: windows }, { name: macos-12, bin-name: darwin }] os: [{ name: ubuntu-22.04, bin-name: linux }, { name: windows-2022, bin-name: windows }, { name: macos-12, bin-name: darwin }]
arch: [amd64, arm64] arch: [amd64, arm64]
exclude: exclude:
- os: { name: windows-2022, bin-name: windows } - os: { name: windows-2022, bin-name: windows }
arch: 'arm64' arch: 'arm64'
- os: { name: macos-12, bin-name: darwin }
arch: 'amd64'
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
ref: ${{ github.event.inputs.ref }} ref: ${{ github.event.inputs.ref }}
# Allows to fetch all history for all branches and tags. Need this for proper versioning. # Allows to fetch all history for all branches and tags. Need this for proper versioning.
fetch-depth: 0 fetch-depth: 0
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v4 uses: actions/setup-go@v5
with: with:
go-version: '1.20' go-version: '1.22'
cache: true
- name: Update Go modules
run: go mod download -json
- name: Build CLI - name: Build CLI
run: make build run: make build
@ -70,32 +64,38 @@ jobs:
run: mv ./bin/neo-go* ./bin/neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}${{ (matrix.os.bin-name == 'windows' && '.exe') || '' }} run: mv ./bin/neo-go* ./bin/neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}${{ (matrix.os.bin-name == 'windows' && '.exe') || '' }}
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }} name: neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}
path: ./bin/neo-go* path: ./bin/neo-go*
if-no-files-found: error if-no-files-found: error
- name: Attach binary to the release as an asset
if: ${{ github.event_name == 'release' }}
run: gh release upload ${{ github.event.release.tag_name }} ./bin/neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}${{ (matrix.os.bin-name == 'windows' && '.exe') || '' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build_image: build_image:
needs: build_cli needs: build_cli
name: Build and push docker image name: Build and push docker image
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
ref: ${{ github.event.inputs.ref }} ref: ${{ github.event.inputs.ref }}
fetch-depth: 0 fetch-depth: 0
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v3
- name: Login to DockerHub - name: Login to DockerHub
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }} if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
uses: docker/login-action@v2 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }} password: ${{ secrets.DOCKERHUB_PASSWORD }}
@ -110,7 +110,7 @@ jobs:
run: echo "latest=,${{ steps.setvars.outputs.repo }}:latest" >> $GITHUB_OUTPUT run: echo "latest=,${{ steps.setvars.outputs.repo }}:latest" >> $GITHUB_OUTPUT
- name: Build and push - name: Build and push
uses: docker/build-push-action@v3 uses: docker/build-push-action@v5
with: with:
context: . context: .
push: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }} push: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
@ -126,21 +126,20 @@ jobs:
runs-on: windows-2022 runs-on: windows-2022
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
ref: ${{ github.event.inputs.ref }} ref: ${{ github.event.inputs.ref }}
fetch-depth: 0 fetch-depth: 0
# For proper `deps` make target execution. # For proper `deps` make target execution.
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v4 uses: actions/setup-go@v5
with: with:
go-version: '1.20' go-version: '1.22'
cache: true
- name: Login to DockerHub - name: Login to DockerHub
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }} if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
uses: docker/login-action@v2 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }} password: ${{ secrets.DOCKERHUB_PASSWORD }}

View file

@ -0,0 +1,11 @@
name: Contribution guidelines
on:
pull_request:
branches:
- master
jobs:
commits_check_job:
name: DCO check
uses: nspcc-dev/.github/.github/workflows/dco.yml@master

View file

@ -1,21 +0,0 @@
name: DCO check
on:
pull_request:
branches:
- master
jobs:
commits_check_job:
runs-on: ubuntu-latest
name: Commits Check
steps:
- name: Get PR Commits
id: 'get-pr-commits'
uses: tim-actions/get-pr-commits@master
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: DCO Check
uses: tim-actions/dco@master
with:
commits: ${{ steps.get-pr-commits.outputs.commits }}

View file

@ -8,7 +8,7 @@ on:
- master - master
types: [opened, synchronize] types: [opened, synchronize]
paths-ignore: paths-ignore:
- 'scripts/**' - 'scripts/*.sh'
- '**/*.md' - '**/*.md'
workflow_dispatch: workflow_dispatch:
@ -18,26 +18,61 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/setup-go@v4 - uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: with:
go-version: '1.20' go-version-file: 'go.mod'
- uses: actions/checkout@v3
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v3 uses: golangci/golangci-lint-action@v4
with: with:
version: latest version: latest
skip-pkg-cache: true # golangci-lint can't work with this cache enabled, ref. https://github.com/golangci/golangci-lint-action/issues/135.
gomodcheck: gomodcheck:
name: Check internal dependencies name: Check internal dependencies
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Check dependencies - name: Check dependencies
run: | run: |
./scripts/check_deps.sh ./scripts/check_deps.sh
- name: Check go.mod is tidy
run: |
go mod tidy
if [[ $(git diff --name-only go.* | grep '' -c) != 0 ]]; then
echo "go mod tidy should be executed before the merge, following packages are unused or out of date:";
git diff go.*;
exit 1;
fi
codegencheck:
name: Check code generated with 'go generate' is up-to-date
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
- name: Install stringer
run: go install golang.org/x/tools/cmd/stringer@latest
- name: Run go generate
run: go generate ./...
- name: Check that autogenerated code is up-to-date
run: |
if [[ $(git diff --name-only | grep '' -c) != 0 ]]; then
echo "Fresh version of autogenerated code should be committed for the following files:";
git diff --name-only;
exit 1;
fi
codeql: codeql:
name: CodeQL name: CodeQL
@ -53,11 +88,11 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v2 uses: github/codeql-action/init@v3
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
@ -68,7 +103,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v2 uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl # 📚 https://git.io/JvXDl
@ -82,41 +117,37 @@ jobs:
# make release # make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v3
test_cover: test_cover:
name: Coverage name: Coverage
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
env: env:
CGO_ENABLED: 0 CGO_ENABLED: 0
GOEXPERIMENT: nocoverageredesign
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: 'true'
- name: Sync VM submodule
run: |
git submodule sync
git submodule update --init
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v4 uses: actions/setup-go@v5
with: with:
go-version: '1.20' go-version: '1.22'
cache: true cache: true
- name: Update Go modules
run: go mod download -json
- name: Write coverage profile - name: Write coverage profile
run: go test -v ./... -coverprofile=./coverage.txt -covermode=atomic -coverpkg=./pkg...,./cli/... run: go test -timeout 15m -v ./... -coverprofile=./coverage.txt -covermode=atomic -coverpkg=./pkg...,./cli/...
- name: Upload coverage results to Codecov - name: Upload coverage results to Codecov
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v4
with: with:
fail_ci_if_error: true # if something is wrong on uploading codecov results, then this job will fail fail_ci_if_error: true # if something is wrong on uploading codecov results, then this job will fail
files: ./coverage.txt files: ./coverage.txt
slug: nspcc-dev/neo-go
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true verbose: true
tests: tests:
@ -124,40 +155,36 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-20.04, windows-2022, macos-12] os: [ubuntu-22.04, windows-2022, macos-12, macos-14]
go_versions: [ '1.18', '1.19', '1.20' ] go_versions: [ '1.20', '1.21', '1.22' ]
exclude: exclude:
# Only latest Go version for Windows and MacOS. # Only latest Go version for Windows and MacOS.
- os: windows-2022 - os: windows-2022
go_versions: '1.18'
- os: windows-2022
go_versions: '1.19'
- os: macos-12
go_versions: '1.18'
- os: macos-12
go_versions: '1.19'
# Exclude latest Go version for Ubuntu as Coverage uses it.
- os: ubuntu-20.04
go_versions: '1.20' go_versions: '1.20'
- os: windows-2022
go_versions: '1.21'
- os: macos-12
go_versions: '1.20'
- os: macos-12
go_versions: '1.21'
- os: macos-14
go_versions: '1.20'
- os: macos-14
go_versions: '1.21'
# Exclude latest Go version for Ubuntu as Coverage uses it.
- os: ubuntu-22.04
go_versions: '1.22'
fail-fast: false fail-fast: false
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: 'true'
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v4 uses: actions/setup-go@v5
with: with:
go-version: '${{ matrix.go_versions }}' go-version: '${{ matrix.go_versions }}'
cache: true
- name: Update Go modules
run: go mod download -json
- name: Sync VM submodule
run: |
git submodule sync
git submodule update --init
- name: Run tests - name: Run tests
run: go test -v -race ./... run: go test -timeout 15m -v -race ./...

4
.gitignore vendored
View file

@ -7,9 +7,6 @@
# Test binary, build with `go test -c` # Test binary, build with `go test -c`
*.test *.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Added by CoZ developers # Added by CoZ developers
vendor/ vendor/
bin/ bin/
@ -54,6 +51,7 @@ testdata/
!pkg/services/notary/testdata !pkg/services/notary/testdata
!pkg/services/oracle/testdata !pkg/services/oracle/testdata
!pkg/smartcontract/testdata !pkg/smartcontract/testdata
!cli/smartcontract/testdata
pkg/vm/testdata/fuzz pkg/vm/testdata/fuzz
!pkg/vm/testdata !pkg/vm/testdata
!pkg/wallet/testdata !pkg/wallet/testdata

View file

@ -2,6 +2,516 @@
This document outlines major changes between releases. This document outlines major changes between releases.
## 0.106.1 "Implication" (3 Jun 2024)
An urgent release that fixes mainnet state difference at block 5462944 which halts
blocks processing starting from the height 5468658. This release requires full node
DB resynchronization for mainnet nodes. T5 testnet DB state is not affected by this
bug (at least up to the current 4087361 height). Thus, DB resynchronisation may be
skipped for testnet nodes. No configuration changes implied.
Bugs fixed:
* mainnet state difference at block 5462944 caused by runtime notification
permissions check against the updated contract state instead of executing state
(#3472)
* unused neofs-contract dependency in the node modules (#3458)
## 0.106.0 "Zephyranthes" (21 May 2024)
We're rolling out a large set of updates including all of Neo 3.7.4 protocol changes:
native contracts update functionality and extended native contract APIs united under
the upcoming Cockatrice hardfork. For smart contract developers an ability to
generate smart contract bindings with dynamic hash is supported as well as a number
of useful extensions for `unwrap` package, compatible NNS smart contract RPC binding
and a lot of other handy enhancements. This release also includes a couple of severe
regression bug fixes affecting the node state. As a bonus of fixing a wide range of
failing tests, we've refactored the node services start and shutdown procedures to
make it more stable. This version drops support for Go 1.19 and requires 1.20+ to
build (with Go 1.22 supported).
Notice that this release requires full node resynchronization for both mainnet
and testnet nodes. Please pay a special attention to the Cockatrice hardfork schedule
and check your configurations. It should be configured for 3967000 of T5 testnet and
5450000 of mainnet. To ensure compatibility your node must be configured
appropriately.
New features:
* native contracts update functionality bound to hardforks (#3402, #3444)
* Cockatrice hardfork planned for 5450000 block of mainnet and 3967000 block of T5
testnet (#3402, #3448, #3402, #3446)
* `CommitteeChanged` events are emitted by NeoToken native contract starting from
Cockatrice hardfork (#3351, #3448)
* `getCommitteeAddress` method of NeoToken native contract is available starting
from Cockatrice hardfork (#3362, #3402)
* `keccak256` method of CryptoLib native contract is available starting from
Cockatrice hardfork (#3301, #3402)
* dynamic contract hash support for smart contract bindings (#3405)
* support `StringCompressed` API for `crypto.PublicKey` (#3408)
* support `Copy` API for `transaction.Transaction` and `payload.P2PNotaryRequest`
(#3407)
* extend `verifyWithECDsa` method of native CryptoLib contract with Keccak256 hasher
starting from Cockatrice and add an example of custom Koblitz-based and
Keccak256-based transaction witness verification (#3425)
* autogenerated `nativehashes` package (#3402, #3431)
* introduce `unwrap.Exception` type for better RPC invocation result exceptions
detection (#3438)
Behavior changes:
* Neo Name Service smart contract RPC binding follows the official N3 implementation
(#3291)
* clear LastGasPerVote NeoToken account info on unvoting (#3349)
* return fault exception (if any) in `unwrap` RPC client helpers (#3356)
* move P2PNotary designation role out of P2PSigExtensions (#3452)
Improvements:
* support `smartcontract.Convertible` interface as RPC Actor and Invoker call
parameters (#3297)
* allow to import multisignature account into wallet without WIF and password
specified (#3293)
* upgrade go-ordered-json dependency to avoid possible node state incompatibility
issues caused by smart contract manifest marshalling (#3331, #3333)
* Go 1.22 support, bump minimum required Go version up to Go 1.20 (#3336)
* a number of dependent libraries are updated to the fresh versions (#3338, #3418)
* improve error message of `System.Crypto.CheckMultisig` interop API handler (#3374)
* upgrade dBFT library to v0.2.0 (#3371, #3413)
* increase `ValidUntilBlock` value for transactions generated by CLI commands
(#3376)
* documentation updates (#3375, #3382)
* let default Notary Actor options be customizable (#3394)
* extend `getversion` RPC response with RPC server settings (#3386)
* make errors related to wallet opening more detailed (#3389)
* adjust error messages of `setExecFeeFactor` and `setStoragePrice` methods of
native PolicyContract (#3406)
* make neotest chain constructor options customizable (#3404)
* format improvements for CLI commands description (#3410)
* make state dumps comparator script more verbose (#3411)
* refactor storage `Get` implementation for BoltDB (#3441)
* add `updatecounter` field to the resulting items of `getnativecontracts` RPC API
call (#3439)
Bugs fixed:
* node panic on committee missing from node configuration (#3294)
* autogenerated RPC bindings do not follow Go naming convention (#3299)
* a batch of failing tests is fixed (#3306, #3313, #3321, #3332, #3337, #3335,
#3344, #3340, #3350, #3355, #3364, #3368, #3377, #3393, #3397, #3392, #3398,
#3400)
* outdated minimum required Go version of boilerplate contract generated by
`neo-go contract init` (#3318)
* outdated address used as an example in RPC client documentation (#3327)
* ungraceful node services shutdown procedure (#3307)
* logging data race on node services shutdown (#3307)
* Map parameter support is missing from RPC server handlers (#3329)
* smart contract storage iterator prefix wasn't copied while iterating over values
(#3336)
* RPC error with -511 code (insufficient funds) returned on `sendrawtransaction` RPC
request should cover multiple cases of sender's insufficient funds (#3360, #3361)
* reentrancy possibility for Notary deposit withdrawal (#3357)
* null `findstorage` RPC response in case of missing storage items (#3385)
* uninitialized named return variables in compiler (#3401)
* wrong debug sequence points after `JUMP*` instructions shortening by compiler
(#3412)
* corrupted genesis block record and application log caused by improper Conflicts
attribute processing (#3437)
* false positive DB-based blocked accounts detection in native PolicyContract leaded
to invalid committee computations and reward distribution made by NeoToken (#3443)
## 0.105.1 "Enumeration" (12 Jan 2024)
This is another v3.6.2-compatible release that fixes mainnet state difference at
block 4688591. It is confirmed to have the same state up to 4723K height (which
is current), but to get proper mainnet state you need to resynchronize your node
from the genesis. T5 testnet state is not affected (at least up to the current
3323K height), thus DB resynchronisation may be skipped for testnet nodes.
Improvements:
* better network services logging (#3287, #3290)
Bugs fixed:
* state difference at block 4688591 of N3 mainnet caused by difference at
characters escaping during manifest's `Extra` field JSON serialisation (#3286)
## 0.105.0 "Designation" (29 Dec 2023)
We're rolling out an update for NeoGo nodes that contains a number of user-facing
API improvements for RPC web-socket notification subsystem, CLI utility, wallet
related packages and not only. Try out our new `--await` CLI option for those
commands that relay transactions to the network to automatically wait for the
on-chain transaction execution result. Subscribe for new block headers with
extended RPC notification subsystem interface. Use contract-based accounts
provided by `wallet` package and `neotest` framework to sign transactions. These
and a set of other improvements are available to our users while this release is
staying compatible with 3.6.2 version of C# node.
This version also delivers a bug fix for consensus node panic caused by improper
native NeoToken cache initialisation. Moreover, there's a set of RPC server side
improvements, thus, we recommend to upgrade both consensus and RPC nodes to
provide more stable consensus node functioning and extended user APIs functionality.
No database resynchronisation is needed.
New features:
* block headers RPC web-socket subscription (#3252)
* --await option to synchronize on transaction execution for CLI commands (#3265)
* partial session-based RPC iterator unwrapping (#3274)
* contract-based transaction signers in neotest framework (#3233)
* AMD64 release binaries for macOS (#3251)
* complex contract signature schemes in wallet.Account (#3256)
Behavior changes:
* basic RPC subscription filter validity checks are implemented on both RPC
client and RPC server sides (#3258)
* filter of notary request event RPC subscription is extended with `type` field
(#3236)
* if available, use block headers RPC web-socket subscription for transaction
awaiting via `waiter` package API (#3283)
Improvements:
* add smart contract storage limits to interop utilities (#3232)
* extend ZKP examples documentation with additional links to PoT ceremony
response files (#3234)
* support Go types in VM emitter API (#3237)
* documentation update (#3239, #3242, #3246)
* BoltDB (go.etcd.io/bbolt) dependency upgrade (#3250)
* CLI code refactoring (#2682)
* extend wallet package to work with byte slice based wallets (#3255)
* export RPC client side transaction awaiting functionality via `waiter` package
(#3265, #3283)
Bugs fixed:
* remove stale `updatehistory` section of `getnativecontracts` RPC response (#3240)
* immediately check RPC client initialisation on access to blocks RPC subscription
API (#3257, #3261)
* fix CN panic caused by unexpected call to native NeoToken cache (#3253)
* make "automatically generated" warning of all automatically generated files
follow the standard (#3280)
## 0.104.0 "Globalization" (27 Nov 2023)
We're updating NeoGo to push out a number of useful updates and protocol
extensions as well as make it compatible with 3.6.2 version of C# node. The most
invasive behaviour changes are VM-level protocol constraints imposed on the size
of serialized stackitems and `NativeActivation` node setting removal. This version
also delivers a set of smaller useful changes in the interoperability layer and
native contract functionality including System.Runtime.CurrentSigners interop,
`strLen` StdLib method and PolicyContract-based transaction attributes pricing
as far as a user-facing `canceltx` CLI command and community-requested
`--relative-path` CLI option.
Node operators must resynchronize their nodes to get fully compatible state
(which is confirmed to be compatible with 3.6.2 for current mainnet up to
block 4483627 and T5 testnet up to block 3078762). Please, ensure your node
configuration doesn't contain `NativeActivations` protocol configuration section
as this logic is hidden under Hardforks starting from the current release.
New features:
* System.Runtime.CurrentSigners interop allowing to get signers of the currently
loaded transaction (#3058)
* `strLen` method to native StdLib contract (#3208)
* transaction attributes pricing regulation via native PolicyContract (#3155)
* `canceltx` CLI command as an alternative to unsupported `canceltransaction` RPC
request (#3223, #3214)
Behaviour changes:
* reduce maximum allowed stackitem.Item size (#3185)
* restrict maximum allowed NEF file size and prohibit large contracts deployment (#3186)
* bind `NativeActivations` node setting to the `Hardforks` setting (#3212)
* introduce serialization limit to stackitem.Item and fail large contracts deploy
wrt this setting (#3218)
* add customizable `MaxRequestBodyBytes` and `MaxRequestHeaderBytes` RPC server
configuration setting (#3221)
Improvements:
* provide more detailed error on attempt to read non-existent service wallet
provided via node configuration file (#3210)
* optimize emit of imported code for autogenerated RPC bindings (#3215)
* documentation update (#3203, #3222)
* add `--relative-path` CLI flag allowing to override configuration-specific relative
paths (#3206)
* update code owners (#3216, @fyrchik will live in our hearts forever)
Bugs fixed:
* unify messages of RPC errors according to the RPC errors NEP (#3199)
* limit maximum allowed number ad depth of transaction signers and witnesses per
RPC request that accept transaction (#3207, #3221)
* forbid unknown fields usage in the node configuration file (#3209)
* enable hardfork-dependant code starting exactly from the block height specified
in the node configuration (#3211)
* require Notary native deposit to be valid for at least one subsequent block after
deposit transaction acceptance (#3211)
* deduplicate unnamed event types for autogenerated RPC bindings and make the
binding generation order strictly defined and stable (#3215, #3220)
* do not panic on trying to compile an import cycle (#3215)
* state difference at block 3002333 of T5 testnet caused by difference at characters
escaping during manifest's `Extra` field JSON serialisation (#3225)
* properly start node services that depend on native RoleManagement contract data
with genesis `Roles` protocol configuration setting specified (#3229)
## 0.103.1 "Verification" (09 Nov 2023)
An urgent 3.6.0-compatible version that contains a hotfix for the bug that
prevents node from starting from the existing database every new dBFT epoch.
Also, the release includes a bugfix that fails any non-zero NEO and GAS
roundtrips from accounts with zero balance.
Although the DB format and storage states were not affected by this release,
the node resynchronization is still recommended for those who want to keep
correct application logs. Resynchronization can be skipped if you're ok with
wrong application logs for some transactions (e.g. CN doesn't care, and RPC node
cares a lot).
Bugs fixed:
* properly initialize cache of native NeoToken contract every new dBFT epoch (#3187)
* forbid non-zero NEO and GAS roundtrips from accounts with zero balance (#3191)
## 0.103.0 "Backwardation" (20 Oct 2023)
A minor 3.6.0-compatible version of NeoGo with new salty ZKP-related
functionality, a large batch of deprecated APIs removal and an experimental
genesis block extension. Build Groth-16 circuits, generate proofs and deploy
verification contracts easily with the new end-to-end ZKP example and `zkpbinding`
NeoGo API. Setup node roles via the node configuration starting from the genesis
block without any painful multisignature transaction forming and invoke any
custom script in the genesis-level transaction with the new `Genesis` protocol
configuration extension. And don't forget to move from deprecated RPC client
APIs, as a lot of them have been removed.
New node configuration format is finally adapted and the deprecated configuration
sections are permanently removed according to the schedule. Pay attention to the
`SecondsPerBlock` protocol configuration section that was replaced by
`TimePerBlock`, a set of node and services address- and port- related configuration
section that were replaced by the new `Addresses` format, direct `UnlockWallet`
consensus configuration that was replaced by a separate `Consensus` section and
a set of node-specific protocol configurations that were moved under a separate
`P2P` section.
This release fixes a set of bugs including a vulnerability introduced by changes
in the transaction conflicts storage scheme implemented in #3061 (a part of
0.102.0 release). With the patch presented, it's impossible to uncontrollably
pollute the storage with malicious conflicting records.
This version is fully compatible with C# node 3.6.0. However, it requires
complete resynchronization on upgrade due to the database storage scheme changes.
New features:
* API for Groth-16 verification contracts autogeneration and end-to-end example for
proving and verifying statements on NeoGo (#3043, #3146)
* introduce genesis protocol extensions: default node roles designation and genesis
transactions (#3168)
Behaviour changes:
* a lot of deprecated functionality is dropped: RPC client old APIs, shared
Notifications channel of WebSocket client, SecondsPerBlock protocol
configuration, old way of services and node address and port configuration, old
P2P related application settings configuration, direct UnlockWallet consensus
configuration, direct node-specific protocol configuration (#3150)
* database scheme is changed by new way of storing the transaction conflicting
records (#3138)
Improvements:
* NeoFS SDK dependency upgrade (#3129)
* gnark and gnark-crypto dependencies upgrade (#3145, #3162, #3163)
* introduce timeout restriction for BoltDB opening (#3148)
* bump code coverage uploading action version (#3153)
* Go 1.21 support, bump minimum required Go version up to Go 1.19 (#3157)
* upgrade golang.org/x/net version (#3158)
* add protocol hardforks configuration to the `getversion` RPC response (#3160)
* format autogenerated smart contract bindings with accordance to standard `go fmt` rules (#3164)
* add "DO NOT EDIT" warning to the autogenerated smart contract bindings (#3167)
Bugs fixed:
* avoid race between `getnextblockvalidators` RPC call handler and blockchain's
block handler routine, significantly refactor native validators caching scheme
(#3110)
* do not panic on failed NeoFS oracle requests (#3129)
* enable Notary subsystem in NeoFS mainnet configuration (#3136)
* reorganize storage scheme for transaction conflicting records to avoid possible attack (#3138)
* properly deserialize wildcard trusts field of smart contract manifest (#3140)
* use more strict GAS limit for transaction network fee calculation via RPC call (#3141)
* avoid WebSocket client request blocking (#3142)
* properly emit big uint64 constants during smart contract compilation (#3147)
* avoid race access to the node version by tests (#3149)
* make FindStorage* RPC client APIs to be always compatible with NeoC# RPC server (#3166)
## 0.102.0 "Aberration" (06 Sep 2023)
Long-awaited feature-packed 3.6.0-compatible version of NeoGo with all the
appropriate protocol updates and a set of tasty improvements and bug
fixes. Groth16 ZKP proof checks are there for contract developers as well as
new opcodes. A huge number of improvements went into the RPC server and
client, new RPCs, improved contract binding generator and standardized
extended error codes make developing dApps much easier.
Users of smart contract utilities and RPC-related Prometheus metrics are
advised to take a look at the deprecated APIs removal schedule
(ROADMAP.md). This version was delayed for quite some time (waiting for 3.6),
so the next minor release (0.103.0) will remove a substantial amount of
compatibility code. It's expected to be released in November with 3.6 protocol
compatibility (3.7 cycle is likely to require more time).
This is also the first version that drops support for Go 1.17 and requires
1.18+ to build (with Go 1.20 supported). Using generics in smart contracts is
not supported yet, but some elements of this support can be implemented in
future versions.
Mainnet and testnet node operators, please pay attention to the Basilisk
hardfork schedule and check your configurations. It will happen at block
2680000 for T5 testnet and 4120000 for mainnet. To ensure compatibility your
node must be configured appropriately. This version requires DB
resynchronization, so schedule your updates accordingly.
New features:
* ZKP proof checking support via CryptoLib native contract (operations with
BLS12-381 curve points) (#2940, #3042)
* System.Storage.Find interop now support "Backwards" flag to iterate in the
opposite direction (#2952)
* `util ops` CLI utility that pretty-prints VM script (#2965)
* `notarypool_unsorted_tx` Prometheus metric for notary-enabled nodes (#2696)
* `CloseNotificationChannelIfFull` WSClient option allowing the client to
close notification channel on overflow (#2988)
* autogenerated RPC bindings for contract events and conversion code from
stackitem.Item to structure (#3008, #3035, #3036, #3087)
* event type inference from contract code (#3008)
* dynamic contract hashes support for RPC bindings (#3012)
* "Basilisk" protocol hardfork support (#3056, #3080, #3086, #3104)
* ABORTMSG and ASSERTMSG VM opcodes (#3066)
* standardized RPC error codes (#3063)
* `findstorage` and `findstoragehistoric` RPC support (#3099)
* `getstoragehistoric` RPC support (#3099)
* `getrawnotarypool` and `getrawnotarytransaction` RPC (#3098)
Behaviour changes:
* deprecated `FromAddress` smart contract helper is dropped from the `util`
interop package (#2941)
* a number of deprecated RPC-related Prometheus counters are permanently
removed (#2941)
* NEP-2 account label will be asked on account import via CLI (#2889)
* hashes and states of native contracts are now accessible via native
ContractManagement API (#2991)
* `serv_node_version` gauge Prometheus metric is marked as deprecated and
replaced by `neogo_version` and `server_id` (#3009)
* strict contract script check is back with Basilisk hardfork, it was
previously removed in 0.101.3 for 3.5 protocol compatibility (#3056)
* JSON number deserialization (via StdLib.jsonDeserialize) changes with
Basilisk hardfork allowing for more precision and handling more corner
cases (#3080)
* notification type errors are treated as fatal after Basilisk hardfork,
before it they're just logged (#3086)
* NULL and non-UTF8 items are not allowed for String event types (#3086)
* `Conflicts` and `NotValidBefore` transaction attributes are no longer NeoGo
extensions, they can be used on regular networks (#2962)
Improvements:
* documentation and example improvements (#2945, #2972, #2979, #3020, #3084,
#3099, #3114, #3116, #3119, #3121)
* `getproof` and `verifyproof` RPC API support in RPC client (#2942)
* Go 1.20 support, bump minimum required Go version up to Go 1.18 (#2908)
* faster state reset process (#2819)
* optimized voting data storage scheme for NEO contract (#2892, #2893)
* NeoFS SDK dependency upgrades (#2995, #3032)
* special exported error returned in case of WSClient disconnection (#3000)
* automatic guessing of contract and manifest filenames for `contract
compile` CLI command and `loadnef` VM CLI command (#3013)
* support for pushing stackitem.Convertible objects via VM script emitter (#3016)
* economic adjustment for ranking of transactions with `Conflicts` attribute (#3031)
* `google.golang.org/grpc` dependency upgrade fixing high severity security
vulnerability (#3055, gRPC is only used to communicate with NeoFS nodes in
the oracle service)
* enforce default RPC server values when it's used as an independent package
(not a part of node) (#3107)
* unwrap.Nothing function for RPC clients (#3117)
* address and reverse hash display in opcode dumps (#3115)
Bugs fixed:
* invalid peer port type returned by `getpeers` RPC response (#2914)
* invalid data source for `mempool_unsorted_tx` Prometheus metric (#2969)
* dBFT library upgrade fixing the ability of a single node to speed up the
process of new blocks creation for the whole network (#3018,
nspcc-dev/dbft#75)
* failing CALLT instructions in VM CLI for loaded NEF files (#3020)
* missing signers check for on-chain conflicting transactions (#3061)
* incorrect sequence point boundaries in debug data (#3074)
* compiler panic on encountering generic code (#3041)
* potential pooled fallback notary transaction changes (#3108)
* lost LastGasPerVote value on NEO state deserialization for non-voting
accounts (#3122)
## 0.101.4 "Yarborough" (01 Aug 2023)
Another one 3.5.0-compatible version that is aimed to fix T5 testnet state
difference that has happened at block 2336911 which leads to inability to process
new blocks since 2418703. The issue is fixed by allowing JSON numbers
unmarshalling from scientific notation to Integer stackitem. Maximum parsing
precision for such numbers is currently restricted by 53 bits. This is a
temporary C#-compatible solution that is likely to change in the future versions
when an appropriate C# node bug is fixed (neo-project/neo#2879).
A set of minor bug fixes is included as well to flush some of the long-awaited
changes that were blocked by the 0.102.0 release delay (caused by v3.6.0 C# node
release delay). In particular, invalid headers returned by an RPC server for
error responses, invalid format of incremental dumps created by CLI and deadlock
on unhealthy RPC server shutdown. Long-awaited `--config-file` CLI option to
start the node providing a single configuration file is added.
T5 testnet chain requires a complete resynchronization for this version. Mainnet
chain resynchronization is recommended, but not required.
New features:
* `--config-file` CLI option allowing to start the node with a single configuration file (#3014)
Improvements:
* blockchain Notary and Oracle services documentation improvement (#2972)
* BoltDB (`go.etcd.io/bbolt`) dependency upgrade that fixes a number of Windows-related issues (#3034)
Bugs fixed:
* panic on node start with invalid configuration (#2968)
* deadlock on unhealthy RPC server shutdown (#2966)
* improper WSClient notification channels managing after disconnection (#2980)
* missing Prometheus metric initialisation on node start (#2992)
* invalid initialisation of native contracts cache (#2994)
* incorrect way of incremental DB dumps creation (#3047)
* Notary contract is allowed to be a sender of main Notary request transaction (#3065)
* discrepancy in signer's witness scope parsing on the RPC server side (#3060)
* Invoker calling API isn't allowed to accept nil parameter (#3067)
* contract RPC Client unwrapper helper can't handle missing contract case (#3072)
* JSON numbers can't be unmarshalled to stackitem from scientific notation (#3073)
* invalid content-type header returned by RPC server on error responses (#3075)
## 0.101.3 "Yuckiness" (08 Jul 2023)
Yet another 3.5.0-compatible emergency version that removes scrupulous
instructions check of smart contract's script on contract deployment or update.
Presence of this check leads to the known T5 testnet state incompatibility
(since 1670095) which causes inability to process new blocks (since 2272533).
It should be noted that the corresponding check was accidentally removed from
the reference C# node implementation way back in neo-project/neo#2266 and added
again in neo-project/neo#2849 which is planned to be a part of the upcoming
3.6.0 C# node release. Thus, changes made in the presented 0.101.3 release will
be reverted afterwards and strict contract script check will be present in the
next 3.6.0-compatible version of NeoGo node.
T5 testnet chain requires a complete resynchronization for this version. Mainnet
chain resynchronization is recommended.
Bugs fixed:
* extra strict contract script check on contract deployment or update is
removed (#3052)
## 0.101.2 "Excavation" (29 Jun 2023)
One more (and unexpected one!) 3.5.0-compatible version that fixes a VM bug
leading to mainnet state incompatibility (since 3672783) which in turn leads
to inability to process new blocks (since 3682290).
Mainnet chain needs to be resynchronized for this version.
Improvements:
* documentation updates (#3029, #2990, #2981)
Bugs fixed:
* incorrect handling of empty Any-type parameter for RPC invocations (#2959)
* incorrect state rollbacks in case of exception during cross-contract call
when the call is made from non-TRYing context (#3046)
## 0.101.1 "Shallowness" (17 Mar 2023) ## 0.101.1 "Shallowness" (17 Mar 2023)
Another 3.5.0-compatible version that delivers important bug fixes and Another 3.5.0-compatible version that delivers important bug fixes and
@ -2099,7 +2609,7 @@ Behavior changes:
* contracts no longer have single entry point, rather they export a set of * contracts no longer have single entry point, rather they export a set of
methods with specific offsets. Go smart contract compiler has been changed methods with specific offsets. Go smart contract compiler has been changed
accordingly to add all exported (as in Go) methods to the manifest accordingly to add all exported (as in Go) methods to the manifest
(but with the first letter being lowercased to match NEP-5 expections, (but with the first letter being lowercased to match NEP-5 expectations,
#1228). Please also refer to examples changes to better see how it affects #1228). Please also refer to examples changes to better see how it affects
contracts, manifests and configuration files (#1296) contracts, manifests and configuration files (#1296)
* native contracts are now called via Neo.Native.Call syscall (#1191) * native contracts are now called via Neo.Native.Call syscall (#1191)

View file

@ -1,6 +1,6 @@
# Builder image # Builder image
# Keep go version in sync with Build GA job. # Keep go version in sync with Build GA job.
FROM golang:1.20-alpine as builder FROM golang:1.22-alpine as builder
# Display go version for information purposes. # Display go version for information purposes.
RUN go version RUN go version

View file

@ -1,75 +1,6 @@
# Builder image # Builder image
FROM mcr.microsoft.com/windows/servercore:ltsc2022 as builder
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';", "$ProgressPreference = 'SilentlyContinue';"]
ENV GIT_VERSION=2.23.0
ENV GIT_TAG=v2.23.0.windows.1
ENV GIT_DOWNLOAD_URL=https://github.com/git-for-windows/git/releases/download/v2.23.0.windows.1/MinGit-2.23.0-64-bit.zip
ENV GIT_DOWNLOAD_SHA256=8f65208f92c0b4c3ae4c0cf02d4b5f6791d539cd1a07b2df62b7116467724735
RUN Write-Host ('Downloading {0} ...' -f $env:GIT_DOWNLOAD_URL); \
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
Invoke-WebRequest -Uri $env:GIT_DOWNLOAD_URL -OutFile 'git.zip'; \
\
Write-Host ('Verifying sha256 ({0}) ...' -f $env:GIT_DOWNLOAD_SHA256); \
if ((Get-FileHash git.zip -Algorithm sha256).Hash -ne $env:GIT_DOWNLOAD_SHA256) { \
Write-Host 'FAILED!'; \
exit 1; \
}; \
\
Write-Host 'Expanding ...'; \
Expand-Archive -Path git.zip -DestinationPath C:\git\.; \
\
Write-Host 'Removing ...'; \
Remove-Item git.zip -Force; \
\
Write-Host 'Updating PATH ...'; \
$env:PATH = 'C:\git\cmd;C:\git\mingw64\bin;C:\git\usr\bin;' + $env:PATH; \
[Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine); \
\
Write-Host 'Verifying install ("git version") ...'; \
git version; \
\
Write-Host 'Complete.';
ENV GOPATH=C:\\go
RUN $newPath = ('{0}\bin;C:\Program Files\Go\bin;{1}' -f $env:GOPATH, $env:PATH); \
Write-Host ('Updating PATH: {0}' -f $newPath); \
[Environment]::SetEnvironmentVariable('PATH', $newPath, [EnvironmentVariableTarget]::Machine);
# Keep go version in sync with Build GA job. # Keep go version in sync with Build GA job.
ENV GOLANG_VERSION=1.20 FROM golang:1.22.0-windowsservercore-ltsc2022 as builder
RUN $url = 'https://go.dev/dl/go1.20.windows-amd64.zip'; \
Write-Host ('Downloading {0} ...' -f $url); \
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
Invoke-WebRequest -Uri $url -OutFile 'go.zip'; \
\
$sha256 = 'e8f6d8bbcf3df58d2ba29818e13b04c2e42ba2e4d90d580720b21c34d10bbf68'; \
Write-Host ('Verifying sha256 ({0}) ...' -f $sha256); \
if ((Get-FileHash go.zip -Algorithm sha256).Hash -ne $sha256) { \
Write-Host 'FAILED!'; \
exit 1; \
}; \
\
Write-Host 'Expanding ...'; \
Expand-Archive go.zip -DestinationPath C:\; \
\
Write-Host 'Moving ...'; \
Move-Item -Path C:\go -Destination 'C:\Program Files\Go'; \
\
Write-Host 'Removing ...'; \
Remove-Item go.zip -Force; \
\
Write-Host 'Verifying install ("go version") ...'; \
go version; \
\
Write-Host 'Complete.';
COPY . /neo-go COPY . /neo-go

View file

@ -1,7 +1,6 @@
MIT License MIT License
Copyright (c) 2018-2022 Anthony De Meulemeester (@anthdm), City of Zion Copyright (c) 2018-2023 NeoSPCC (@nspcc-dev), Anthony De Meulemeester (@anthdm), City of Zion community (@CityOfZion)
community (@CityOfZion), NeoSPCC (@nspcc-dev)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -3,7 +3,7 @@ REPONAME = "neo-go"
NETMODE ?= "privnet" NETMODE ?= "privnet"
BINARY=neo-go BINARY=neo-go
BINARY_PATH=./bin/$(BINARY)$(shell go env GOEXE) BINARY_PATH=./bin/$(BINARY)$(shell go env GOEXE)
GO_VERSION ?= 1.18 GO_VERSION ?= 1.20
DESTDIR = "" DESTDIR = ""
SYSCONFIGDIR = "/etc" SYSCONFIGDIR = "/etc"
BINDIR = "/usr/bin" BINDIR = "/usr/bin"

View file

@ -12,7 +12,7 @@
<hr /> <hr />
[![codecov](https://codecov.io/gh/nspcc-dev/neo-go/branch/master/graph/badge.svg)](https://codecov.io/gh/nspcc-dev/neo-go) [![codecov](https://codecov.io/gh/nspcc-dev/neo-go/branch/master/graph/badge.svg)](https://codecov.io/gh/nspcc-dev/neo-go)
[![GithubWorkflows Tests](https://github.com/nspcc-dev/neo-go/actions/workflows/run_tests.yml/badge.svg)](https://github.com/nspcc-dev/neo-go/actions/workflows/run_tests.yml) [![GithubWorkflows Tests](https://github.com/nspcc-dev/neo-go/actions/workflows/tests.yml/badge.svg)](https://github.com/nspcc-dev/neo-go/actions/workflows/tests.yml)
[![Report](https://goreportcard.com/badge/github.com/nspcc-dev/neo-go)](https://goreportcard.com/report/github.com/nspcc-dev/neo-go) [![Report](https://goreportcard.com/badge/github.com/nspcc-dev/neo-go)](https://goreportcard.com/report/github.com/nspcc-dev/neo-go)
[![GoDoc](https://godoc.org/github.com/nspcc-dev/neo-go?status.svg)](https://godoc.org/github.com/nspcc-dev/neo-go) [![GoDoc](https://godoc.org/github.com/nspcc-dev/neo-go?status.svg)](https://godoc.org/github.com/nspcc-dev/neo-go)
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/nspcc-dev/neo-go?sort=semver) ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/nspcc-dev/neo-go?sort=semver)
@ -51,7 +51,7 @@ NeoGo, `:latest` points to the latest release) or build yourself.
### Building ### Building
Building NeoGo requires Go 1.18+ and `make`: Building NeoGo requires Go 1.20+ and `make`:
``` ```
make make
@ -180,9 +180,8 @@ describing the feature/topic you are going to implement.
# Contact # Contact
- [@roman-khimov](https://github.com/roman-khimov) on GitHub
- [@AnnaShaleva](https://github.com/AnnaShaleva) on GitHub - [@AnnaShaleva](https://github.com/AnnaShaleva) on GitHub
- [@fyrchik](https://github.com/fyrchik) on GitHub - [@roman-khimov](https://github.com/roman-khimov) on GitHub
- Reach out to us on the [Neo Discord](https://discordapp.com/invite/R8v48YA) channel - Reach out to us on the [Neo Discord](https://discordapp.com/invite/R8v48YA) channel
# License # License

View file

@ -7,14 +7,13 @@ functionality.
## Versions 0.7X.Y (as needed) ## Versions 0.7X.Y (as needed)
* Neo 2.0 support (bug fixes, minor functionality additions) * Neo 2.0 support (bug fixes, minor functionality additions)
## Version 0.102.0 (~March 2022) ## Version 0.107.0 (~Jun-Jul 2024)
* 3.6.0 compatibility * protocol updates
* bug fixes
* node resynchronisation from local DB
* CLI library upgrade
## Version 0.102.1 (~April 2022) ## Version 1.0 (2024, TBD)
* improved RPC error codes
* extended data types for iterators to be used by RPC wrapper generator
## Version 1.0 (2023, TBD)
* stable version * stable version
# Deprecated functionality # Deprecated functionality
@ -26,100 +25,47 @@ APIs/commands/configurations will be removed and here is a list of scheduled
breaking changes. Consider changing your code/scripts/configurations if you're breaking changes. Consider changing your code/scripts/configurations if you're
using anything mentioned here. using anything mentioned here.
## Old RPC client APIs
A huge set of RPC client APIs was deprecated in versions 0.99.2 and 0.99.3
(August-September 2022), including very frequently used ones like
SignAndPushInvocationTx, AddNetworkFee, TransferNEP17. A new set of
invoker/actor/unwrap/nep17/etc packages was introduced decoupling these
functions from RPC client and simplifying typical backend code. Please refer
to rpcclient package documentation for specific replacements for each of these
APIs and convert your code to using them.
While a lot of the code is already converted to new APIs, old ones still can
be used in some code not known to us. Therefore we will remove old APIs not
earlier than May 2023, with 0.103.0 release.
## WSClient Notifications channel and SubscribeFor* APIs
Version 0.99.5 of NeoGo introduces a new set of subscription APIs that gives
more control to the WSClient user that can pass specific channels to be used
for specific subscriptions now. Old APIs and generic Notifications channel are
still available, but will be removed, so please convert your code to using new
Receive* APIs.
Removal of these APIs is scheduled for May 2023 (~0.103.0 release).
## SecondsPerBlock protocol configuration
With 0.100.0 version SecondsPerBlock protocol configuration setting was
deprecated and replaced by a bit more generic and precise TimePerBlock
(allowing for subsecond time). An informational message is printed on node
startup to inform about this, it's very easy to deal with this configuration
change, just replace one line.
Removal of SecondsPerBlock is scheduled for May-June 2023 (~0.103.0 release).
## Services/node address and port configuration
Version 0.100.0 of NeoGo introduces a multiple binding addresses capability to
the node's services (RPC server, TLS RPC configuration, Prometheus, Pprof) and
the node itself. It allows to specify several listen addresses/ports using an
array of "address:port" pairs in the service's `Addresses` config section and
array of "address:port:announcedPort" tuples in the `ApplicationConfiguration`'s
`Addresses` node config section. Deprecated `Address` and `Port` sections of
`RPC`, `Prometheus`, `Pprof` subsections of the `ApplicationConfiguration`
as far as the one of RPC server's `TLSConfig` are still available, but will be
removed, so please convert your node configuration file to use new `P2P`-level
`Addresses` section for the node services. Deprecated `Address`, `NodePort` and
`AnnouncedPort` sections of `ApplicationConfiguration` will also be removed
eventually, so please update your node configuration file to use `Addresses`
section for the P2P addresses configuration.
Removal of these config sections is scheduled for May-June 2023 (~0.103.0 release).
## P2P application settings configuration
Version 0.100.0 of NeoGo marks the following P2P application settings as
deprecated: `AttemptConnPeers`, `BroadcastFactor`, `DialTimeout`,
`ExtensiblePoolSize`, `MaxPeers`, `MinPeers`, `PingInterval`, `PingTimeout`,
`ProtoTickInterval`. These settings are moved to a separate `P2P` section of
`ApplicationConfiguration`. The `DialTimeout`, `PingInterval`, `PingTimeout`,
`ProtoTickInterval` settings are converted to more precise `Duration` format
(allowing for subsecond time). Please, update your node configuration (all you
need is to move specified settings under the `P2P` section and convert
time-related settings to `Duration` format).
Removal of deprecated P2P related application settings is scheduled for May-June
2023 (~0.103.0 release).
## Direct UnlockWallet consensus configuration
Top-level UnlockWallet section in ApplicationConfiguration was used as an
implicit consensus service configuration, now this setting (with Enabled flag)
is moved into a section of its own (Consensus). Old configurations are still
supported, but this support will eventually be removed.
Removal of this compatibility code is scheduled for May-June 2023 (~0.103.0
release).
## Node-specific configuration moved from Protocol to Application
GarbageCollectionPeriod, KeepOnlyLatestState, RemoveUntraceableBlocks,
SaveStorageBatch and VerifyBlocks settings were moved from
ProtocolConfiguration to ApplicationConfiguration in version 0.100.0. Old
configurations are still supported, except for VerifyBlocks which is replaced
by SkipBlockVerification with inverted meaning (and hence an inverted default)
for security reasons.
Removal of these options from ProtocolConfiguration is scheduled for May-June
2023 (~0.103.0 release).
## GetPeers RPC server response type changes and RPC client support ## GetPeers RPC server response type changes and RPC client support
GetPeers RPC command returns a list of Peers where the port type has changed from GetPeers RPC command returns a list of Peers where the port type has changed from
string to uint16 to match C#. The RPC client currently supports unmarshalling both string to uint16 to match C#. The RPC client currently supports unmarshalling both
formats. formats.
Removal of Peer unmarshalling with string based ports is scheduled for ~September 2023 Removal of Peer unmarshalling with string based ports is scheduled for Jun-Jul 2024
(~0.105.0 release). (~0.107.0 release).
## `NEOBalance` from stack item
We check struct items count before convert LastGasPerVote to let RPC client be compatible with
old versions.
Removal of this compatiblility code is scheduled for Jun-Jul 2024.
## `serv_node_version` Prometheus gauge metric
This metric is replaced by the new `neogo_version` and `server_id` Prometheus gauge
metrics with proper version formatting. `neogo_version` contains NeoGo version
hidden under `version` label and `server_id` contains network server ID hidden
under `server_id` label.
Removal of `serv_node_version` is scheduled for Jun-Jul 2024 (~0.107.0 release).
## RPC error codes returned by old versions and C#-nodes
NeoGo retains certain deprecated error codes: `neorpc.ErrCompatGeneric`,
`neorpc.ErrCompatNoOpenedWallet`. They returned by nodes not compliant with the
neo-project/proposals#156 (NeoGo pre-0.102.0 and all known C# versions).
Removal of the deprecated RPC error codes is planned for Jun-Jul 2024 (~0.107.0
release).
## Block based web-socket waiter transaction awaiting
Web-socket RPC based `waiter.EventWaiter` uses `header_of_added_block` notifications
subscription to manage transaction awaiting. To support old NeoGo RPC servers
(older than 0.105.0) that do not have block headers subscription ability,
event-based waiter fallbacks to the old way of block monitoring with
`block_added` notifications subscription.
Removal of stale RPC server compatibility code from `waiter.EventWaiter` is
scheduled for Jun-Jul 2024 (~0.107.0 release).

View file

@ -4,11 +4,12 @@ import (
"testing" "testing"
"github.com/nspcc-dev/neo-go/internal/testcli" "github.com/nspcc-dev/neo-go/internal/testcli"
"github.com/nspcc-dev/neo-go/internal/versionutil"
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
) )
func TestCLIVersion(t *testing.T) { func TestCLIVersion(t *testing.T) {
config.Version = "0.90.0-test" // Zero-length version string disables '--version' completely. config.Version = versionutil.TestVersion // Zero-length version string disables '--version' completely.
e := testcli.NewExecutor(t, false) e := testcli.NewExecutor(t, false)
e.Run(t, "neo-go", "--version") e.Run(t, "neo-go", "--version")
e.CheckNextLine(t, "^NeoGo") e.CheckNextLine(t, "^NeoGo")

View file

@ -84,8 +84,8 @@ const (
* 'dead' is a byte array with a value of 'dead' * 'dead' is a byte array with a value of 'dead'
* 'string:dead' is a string with a value of 'dead' * 'string:dead' is a string with a value of 'dead'
* 'filebytes:my_data.txt' is bytes decoded from a content of my_data.txt * 'filebytes:my_data.txt' is bytes decoded from a content of my_data.txt
* 'AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y' is a hash160 with a value * 'NSiVJYZej4XsxG5CUpdwn7VRQk8iiiDMPM' is a hash160 with a value
of '23ba2703c53263e8d6e522dc32203339dcd8eee9' of '682cca3ebdc66210e5847d7f8115846586079d4a'
* '\4\2' is an integer with a value of 42 * '\4\2' is an integer with a value of 42
* '\\4\2' is a string with a value of '\42' * '\\4\2' is a string with a value of '\42'
* 'string:string' is a string with a value of 'string' * 'string:string' is a string with a value of 'string'

View file

@ -1,7 +1,6 @@
package cmdargs package cmdargs
import ( import (
"encoding/hex"
"strings" "strings"
"testing" "testing"
@ -45,7 +44,7 @@ func TestParseCosigner(t *testing.T) {
Scopes: transaction.CalledByEntry | transaction.CustomContracts, Scopes: transaction.CalledByEntry | transaction.CustomContracts,
AllowedContracts: []util.Uint160{c1, c2}, AllowedContracts: []util.Uint160{c1, c2},
}, },
acc.StringLE() + ":CustomGroups:" + hex.EncodeToString(priv.PublicKey().Bytes()): { acc.StringLE() + ":CustomGroups:" + priv.PublicKey().StringCompressed(): {
Account: acc, Account: acc,
Scopes: transaction.CustomGroups, Scopes: transaction.CustomGroups,
AllowedGroups: keys.PublicKeys{priv.PublicKey()}, AllowedGroups: keys.PublicKeys{priv.PublicKey()},

View file

@ -14,6 +14,7 @@ import (
"testing" "testing"
"github.com/nspcc-dev/neo-go/internal/testcli" "github.com/nspcc-dev/neo-go/internal/testcli"
"github.com/nspcc-dev/neo-go/internal/versionutil"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
@ -29,6 +30,9 @@ const (
nftOwnerAddr = "NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB" nftOwnerAddr = "NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB"
nftOwnerWallet = "../../examples/my_wallet.json" nftOwnerWallet = "../../examples/my_wallet.json"
nftOwnerPass = "qwerty" nftOwnerPass = "qwerty"
// Keep contract NEFs consistent between runs.
_ = versionutil.TestVersion
) )
func TestNEP11Import(t *testing.T) { func TestNEP11Import(t *testing.T) {
@ -324,6 +328,14 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...) e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
checkBalanceResult(t, nftOwnerAddr, tokenID1) checkBalanceResult(t, nftOwnerAddr, tokenID1)
// check --await flag
tokenID2 := mint(t)
e.In.WriteString(nftOwnerPass + "\r")
e.Run(t, append(cmdTransfer, "--await", "--id", hex.EncodeToString(tokenID2))...)
e.CheckAwaitableTxPersisted(t)
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
checkBalanceResult(t, nftOwnerAddr, tokenID1)
// transfer: good, to NEP-11-Payable contract, with data // transfer: good, to NEP-11-Payable contract, with data
verifyH := deployVerifyContract(t, e) verifyH := deployVerifyContract(t, e)
cmdTransfer = []string{ cmdTransfer = []string{

View file

@ -19,19 +19,34 @@ import (
func TestNEP17Balance(t *testing.T) { func TestNEP17Balance(t *testing.T) {
e := testcli.NewExecutor(t, true) e := testcli.NewExecutor(t, true)
args := []string{
"neo-go", "wallet", "nep17", "multitransfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--from", testcli.ValidatorAddr,
"GAS:" + testcli.TestWalletMultiAccount1 + ":1",
"NEO:" + testcli.TestWalletMultiAccount1 + ":10",
"GAS:" + testcli.TestWalletMultiAccount3 + ":3",
"--force",
}
e.In.WriteString("one\r")
e.Run(t, args...)
e.CheckTxPersisted(t)
cmdbalance := []string{"neo-go", "wallet", "nep17", "balance"} cmdbalance := []string{"neo-go", "wallet", "nep17", "balance"}
cmdbase := append(cmdbalance, cmdbase := append(cmdbalance,
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet, "--wallet", testcli.TestWalletMultiPath,
) )
cmd := append(cmdbase, "--address", testcli.ValidatorAddr) cmd := append(cmdbase, "--address", testcli.TestWalletMultiAccount1)
t.Run("excessive parameters", func(t *testing.T) { t.Run("excessive parameters", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--token", "NEO", "gas")...) e.RunWithError(t, append(cmd, "--token", "NEO", "gas")...)
}) })
t.Run("NEO", func(t *testing.T) { t.Run("NEO", func(t *testing.T) {
b, index := e.Chain.GetGoverningTokenBalance(testcli.ValidatorHash) b, index := e.Chain.GetGoverningTokenBalance(testcli.TestWalletMultiAccount1Hash)
checkResult := func(t *testing.T) { checkResult := func(t *testing.T) {
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.ValidatorAddr) e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)") e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$") e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10)) e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
@ -48,65 +63,53 @@ func TestNEP17Balance(t *testing.T) {
}) })
t.Run("GAS", func(t *testing.T) { t.Run("GAS", func(t *testing.T) {
e.Run(t, append(cmd, "--token", "GAS")...) e.Run(t, append(cmd, "--token", "GAS")...)
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.ValidatorAddr) e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)") e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
b := e.Chain.GetUtilityTokenBalance(testcli.ValidatorHash) b := e.Chain.GetUtilityTokenBalance(testcli.TestWalletMultiAccount1Hash)
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(b.Int64()).String()+"$") e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(b.Int64()).String()+"$")
}) })
t.Run("zero balance of known token", func(t *testing.T) { t.Run("zero balance of known token", func(t *testing.T) {
e.Run(t, append(cmdbase, []string{"--token", "NEO"}...)...) e.Run(t, append(cmdbase, []string{"--token", "NEO", "--address", testcli.TestWalletMultiAccount2}...)...)
addr1, err := address.StringToUint160("Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn") e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount2)
require.NoError(t, err)
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr1))
e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)") e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(0).String()+"$") e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(0).String()+"$")
e.CheckNextLine(t, "^\\s*Updated:") e.CheckNextLine(t, "^\\s*Updated:")
e.CheckNextLine(t, "^\\s*$") e.CheckEOF(t)
}) })
t.Run("all accounts", func(t *testing.T) { t.Run("all accounts", func(t *testing.T) {
e.Run(t, cmdbase...) e.Run(t, cmdbase...)
addr1, err := address.StringToUint160("Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn")
require.NoError(t, err)
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr1))
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
balance := e.Chain.GetUtilityTokenBalance(addr1)
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
e.CheckNextLine(t, "^\\s*Updated:")
e.CheckNextLine(t, "^\\s*$")
addr2, err := address.StringToUint160("NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq") e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount1)
require.NoError(t, err)
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr2))
e.CheckNextLine(t, "^\\s*$")
addr3, err := address.StringToUint160("NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP")
require.NoError(t, err)
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr3))
// The order of assets is undefined. // The order of assets is undefined.
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
line := e.GetNextLine(t) line := e.GetNextLine(t)
if strings.Contains(line, "GAS") { if strings.Contains(line, "GAS") {
e.CheckLine(t, line, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)") e.CheckLine(t, line, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
balance = e.Chain.GetUtilityTokenBalance(addr3) balance := e.Chain.GetUtilityTokenBalance(testcli.TestWalletMultiAccount1Hash)
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$") e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
e.CheckNextLine(t, "^\\s*Updated:") e.CheckNextLine(t, "^\\s*Updated:")
} else { } else {
balance, index := e.Chain.GetGoverningTokenBalance(testcli.ValidatorHash) balance, index := e.Chain.GetGoverningTokenBalance(testcli.TestWalletMultiAccount1Hash)
e.CheckLine(t, line, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)") e.CheckLine(t, line, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+balance.String()+"$") e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+balance.String()+"$")
e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10)) e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
} }
} }
e.CheckNextLine(t, "^\\s*$") e.CheckNextLine(t, "^\\s*$")
addr4, err := address.StringToUint160("NiFxRcC5Anz9pmqQyMHh5vamBUZDbRRRzA") // deployed verify.go contract
require.NoError(t, err) e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount2)
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr4)) e.CheckNextLine(t, "^\\s*$")
e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount3)
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
balance := e.Chain.GetUtilityTokenBalance(testcli.TestWalletMultiAccount3Hash)
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
e.CheckNextLine(t, "^\\s*Updated:")
e.CheckEOF(t) e.CheckEOF(t)
}) })
t.Run("Bad token", func(t *testing.T) { t.Run("Bad token", func(t *testing.T) {
e.Run(t, append(cmd, "--token", "kek")...) e.Run(t, append(cmd, "--token", "kek")...)
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.ValidatorAddr) e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
e.CheckNextLine(t, `^\s*Can't find data for "kek" token\s*`) e.CheckNextLine(t, `^\s*Can't find data for "kek" token\s*`)
e.CheckEOF(t) e.CheckEOF(t)
}) })
@ -223,12 +226,19 @@ func TestNEP17Transfer(t *testing.T) {
"neo-go", "wallet", "nep17", "transfer", "neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0], "--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet, "--wallet", testcli.ValidatorWallet,
"--to", address.Uint160ToString(e.Chain.GetNotaryContractScriptHash()),
"--token", "GAS", "--token", "GAS",
"--amount", "1", "--amount", "1",
"--from", testcli.ValidatorAddr,
"--force", "--force",
"[", testcli.ValidatorAddr, strconv.Itoa(int(validTil)), "]"} "--from", testcli.ValidatorAddr}
t.Run("with await", func(t *testing.T) {
e.In.WriteString("one\r")
e.Run(t, append(cmd, "--to", nftOwnerAddr, "--await")...)
e.CheckAwaitableTxPersisted(t)
})
cmd = append(cmd, "--to", address.Uint160ToString(e.Chain.GetNotaryContractScriptHash()),
"[", testcli.ValidatorAddr, strconv.Itoa(int(validTil)), "]")
t.Run("with data", func(t *testing.T) { t.Run("with data", func(t *testing.T) {
e.In.WriteString("one\r") e.In.WriteString("one\r")

View file

@ -11,33 +11,56 @@ import (
"os" "os"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpcclient" "github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker" "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/urfave/cli" "github.com/urfave/cli"
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
"golang.org/x/term"
"gopkg.in/yaml.v3"
) )
// DefaultTimeout is the default timeout used for RPC requests. const (
const DefaultTimeout = 10 * time.Second // DefaultTimeout is the default timeout used for RPC requests.
DefaultTimeout = 10 * time.Second
// DefaultAwaitableTimeout is the default timeout used for RPC requests that
// require transaction awaiting. It is set to the approximate time of three
// Neo N3 mainnet blocks accepting.
DefaultAwaitableTimeout = 3 * 15 * time.Second
)
// RPCEndpointFlag is a long flag name for an RPC endpoint. It can be used to // RPCEndpointFlag is a long flag name for an RPC endpoint. It can be used to
// check for flag presence in the context. // check for flag presence in the context.
const RPCEndpointFlag = "rpc-endpoint" const RPCEndpointFlag = "rpc-endpoint"
// Wallet is a set of flags used for wallet operations.
var Wallet = []cli.Flag{cli.StringFlag{
Name: "wallet, w",
Usage: "wallet to use to get the key for transaction signing; conflicts with --wallet-config flag",
}, cli.StringFlag{
Name: "wallet-config",
Usage: "path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag"},
}
// Network is a set of flags for choosing the network to operate on // Network is a set of flags for choosing the network to operate on
// (privnet/mainnet/testnet). // (privnet/mainnet/testnet).
var Network = []cli.Flag{ var Network = []cli.Flag{
cli.BoolFlag{Name: "privnet, p", Usage: "use private network configuration"}, cli.BoolFlag{Name: "privnet, p", Usage: "use private network configuration (if --config-file option is not specified)"},
cli.BoolFlag{Name: "mainnet, m", Usage: "use mainnet network configuration"}, cli.BoolFlag{Name: "mainnet, m", Usage: "use mainnet network configuration (if --config-file option is not specified)"},
cli.BoolFlag{Name: "testnet, t", Usage: "use testnet network configuration"}, cli.BoolFlag{Name: "testnet, t", Usage: "use testnet network configuration (if --config-file option is not specified)"},
cli.BoolFlag{Name: "unittest", Hidden: true}, cli.BoolFlag{Name: "unittest", Hidden: true},
} }
@ -63,7 +86,21 @@ var Historic = cli.StringFlag{
// Config is a flag for commands that use node configuration. // Config is a flag for commands that use node configuration.
var Config = cli.StringFlag{ var Config = cli.StringFlag{
Name: "config-path", Name: "config-path",
Usage: "path to directory with configuration files", Usage: "path to directory with per-network configuration files (may be overridden by --config-file option for the configuration file)",
}
// ConfigFile is a flag for commands that use node configuration and provide
// path to the specific config file instead of config path.
var ConfigFile = cli.StringFlag{
Name: "config-file",
Usage: "path to the node configuration file (overrides --config-path option)",
}
// RelativePath is a flag for commands that use node configuration and provide
// a prefix to all relative paths in config files.
var RelativePath = cli.StringFlag{
Name: "relative-path",
Usage: "a prefix to all relative paths in the node configuration file",
} }
// Debug is a flag for commands that allow node in debug mode usage. // Debug is a flag for commands that allow node in debug mode usage.
@ -74,6 +111,8 @@ var Debug = cli.BoolFlag{
var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'") var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'")
var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash") var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash")
var errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag")
var errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
// GetNetwork examines Context's flags and returns the appropriate network. It // GetNetwork examines Context's flags and returns the appropriate network. It
// defaults to PrivNet if no flags are given. // defaults to PrivNet if no flags are given.
@ -97,6 +136,9 @@ func GetTimeoutContext(ctx *cli.Context) (context.Context, func()) {
if dur == 0 { if dur == 0 {
dur = DefaultTimeout dur = DefaultTimeout
} }
if !ctx.IsSet("timeout") && ctx.Bool("await") {
dur = DefaultAwaitableTimeout
}
return context.WithTimeout(context.Background(), dur) return context.WithTimeout(context.Background(), dur)
} }
@ -152,11 +194,18 @@ func GetRPCWithInvoker(gctx context.Context, ctx *cli.Context, signers []transac
// GetConfigFromContext looks at the path and the mode flags in the given config and // GetConfigFromContext looks at the path and the mode flags in the given config and
// returns an appropriate config. // returns an appropriate config.
func GetConfigFromContext(ctx *cli.Context) (config.Config, error) { func GetConfigFromContext(ctx *cli.Context) (config.Config, error) {
configPath := "./config" var (
configFile = ctx.String("config-file")
relativePath = ctx.String("relative-path")
)
if len(configFile) != 0 {
return config.LoadFile(configFile, relativePath)
}
var configPath = "./config"
if argCp := ctx.String("config-path"); argCp != "" { if argCp := ctx.String("config-path"); argCp != "" {
configPath = argCp configPath = argCp
} }
return config.Load(configPath, GetNetwork(ctx)) return config.Load(configPath, GetNetwork(ctx), relativePath)
} }
var ( var (
@ -171,6 +220,7 @@ var (
// If logPath is configured -- function creates a dir and a file for logging. // If logPath is configured -- function creates a dir and a file for logging.
// If logPath is configured on Windows -- function returns closer to be // If logPath is configured on Windows -- function returns closer to be
// able to close sink for the opened log output file. // able to close sink for the opened log output file.
// If the program is run in TTY then logger adds timestamp to its entries.
func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.Logger, *zap.AtomicLevel, func() error, error) { func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.Logger, *zap.AtomicLevel, func() error, error) {
var ( var (
level = zapcore.InfoLevel level = zapcore.InfoLevel
@ -191,7 +241,11 @@ func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.
cc.DisableStacktrace = true cc.DisableStacktrace = true
cc.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder cc.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder
cc.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder cc.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder if term.IsTerminal(int(os.Stdout.Fd())) {
cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
} else {
cc.EncoderConfig.EncodeTime = func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {}
}
cc.Encoding = "console" cc.Encoding = "console"
cc.Level = zap.NewAtomicLevelAt(level) cc.Level = zap.NewAtomicLevelAt(level)
cc.Sampling = nil cc.Sampling = nil
@ -249,3 +303,108 @@ func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.
log, err := cc.Build() log, err := cc.Build()
return log, &cc.Level, _winfileSinkCloser, err return log, &cc.Level, _winfileSinkCloser, err
} }
// GetRPCWithActor returns an RPC client instance and Actor instance for the given context.
func GetRPCWithActor(gctx context.Context, ctx *cli.Context, signers []actor.SignerAccount) (*rpcclient.Client, *actor.Actor, cli.ExitCoder) {
c, err := GetRPCClient(gctx, ctx)
if err != nil {
return nil, nil, err
}
a, actorErr := actor.New(c, signers)
if actorErr != nil {
c.Close()
return nil, nil, cli.NewExitError(fmt.Errorf("failed to create Actor: %w", actorErr), 1)
}
return c, a, nil
}
// GetAccFromContext returns account and wallet from context. If address is not set, default address is used.
func GetAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error) {
var addr util.Uint160
wPath := ctx.String("wallet")
walletConfigPath := ctx.String("wallet-config")
if len(wPath) != 0 && len(walletConfigPath) != 0 {
return nil, nil, errConflictingWalletFlags
}
if len(wPath) == 0 && len(walletConfigPath) == 0 {
return nil, nil, errNoWallet
}
var pass *string
if len(walletConfigPath) != 0 {
cfg, err := ReadWalletConfig(walletConfigPath)
if err != nil {
return nil, nil, err
}
wPath = cfg.Path
pass = &cfg.Password
}
wall, err := wallet.NewWalletFromFile(wPath)
if err != nil {
return nil, nil, err
}
addrFlag := ctx.Generic("address").(*flags.Address)
if addrFlag.IsSet {
addr = addrFlag.Uint160()
} else {
addr = wall.GetChangeAddress()
if addr.Equals(util.Uint160{}) {
return nil, wall, errors.New("can't get default address")
}
}
acc, err := GetUnlockedAccount(wall, addr, pass)
return acc, wall, err
}
// GetUnlockedAccount returns account from wallet, address and uses pass to unlock specified account if given.
// If the password is not given, then it is requested from user.
func GetUnlockedAccount(wall *wallet.Wallet, addr util.Uint160, pass *string) (*wallet.Account, error) {
acc := wall.GetAccount(addr)
if acc == nil {
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
}
if acc.CanSign() || acc.EncryptedWIF == "" {
return acc, nil
}
if pass == nil {
rawPass, err := input.ReadPassword(
fmt.Sprintf("Enter account %s password > ", address.Uint160ToString(addr)))
if err != nil {
return nil, fmt.Errorf("Error reading password: %w", err)
}
trimmed := strings.TrimRight(string(rawPass), "\n")
pass = &trimmed
}
err := acc.Decrypt(*pass, wall.Scrypt)
if err != nil {
return nil, err
}
return acc, nil
}
// ReadWalletConfig reads wallet config from the given path.
func ReadWalletConfig(configPath string) (*config.Wallet, error) {
file, err := os.Open(configPath)
if err != nil {
return nil, err
}
defer file.Close()
configData, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("unable to read wallet config: %w", err)
}
cfg := &config.Wallet{}
err = yaml.Unmarshal(configData, &cfg)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal wallet config YAML: %w", err)
}
return cfg, nil
}

View file

@ -3,7 +3,6 @@ package query
import ( import (
"bytes" "bytes"
"encoding/base64" "encoding/base64"
"encoding/hex"
"fmt" "fmt"
"sort" "sort"
"strconv" "strconv"
@ -111,7 +110,10 @@ func queryTx(ctx *cli.Context) error {
} }
} }
DumpApplicationLog(ctx, res, &txOut.Transaction, &txOut.TransactionMetadata, ctx.Bool("verbose")) err = DumpApplicationLog(ctx, res, &txOut.Transaction, &txOut.TransactionMetadata, ctx.Bool("verbose"))
if err != nil {
return cli.NewExitError(err, 1)
}
return nil return nil
} }
@ -120,47 +122,49 @@ func DumpApplicationLog(
res *result.ApplicationLog, res *result.ApplicationLog,
tx *transaction.Transaction, tx *transaction.Transaction,
txMeta *result.TransactionMetadata, txMeta *result.TransactionMetadata,
verbose bool) { verbose bool) error {
buf := bytes.NewBuffer(nil) var buf []byte
// Ignore the errors below because `Write` to buffer doesn't return error. buf = fmt.Appendf(buf, "Hash:\t%s\n", tx.Hash().StringLE())
tw := tabwriter.NewWriter(buf, 0, 4, 4, '\t', 0) buf = fmt.Appendf(buf, "OnChain:\t%t\n", res != nil)
_, _ = tw.Write([]byte("Hash:\t" + tx.Hash().StringLE() + "\n"))
_, _ = tw.Write([]byte(fmt.Sprintf("OnChain:\t%t\n", res != nil)))
if res == nil { if res == nil {
_, _ = tw.Write([]byte("ValidUntil:\t" + strconv.FormatUint(uint64(tx.ValidUntilBlock), 10) + "\n")) buf = fmt.Appendf(buf, "ValidUntil:\t%s\n", strconv.FormatUint(uint64(tx.ValidUntilBlock), 10))
} else { } else {
if txMeta != nil { if txMeta != nil {
_, _ = tw.Write([]byte("BlockHash:\t" + txMeta.Blockhash.StringLE() + "\n")) buf = fmt.Appendf(buf, "BlockHash:\t%s\n", txMeta.Blockhash.StringLE())
} }
if len(res.Executions) != 1 { if len(res.Executions) != 1 {
_, _ = tw.Write([]byte("Success:\tunknown (no execution data)\n")) buf = fmt.Appendf(buf, "Success:\tunknown (no execution data)\n")
} else { } else {
_, _ = tw.Write([]byte(fmt.Sprintf("Success:\t%t\n", res.Executions[0].VMState == vmstate.Halt))) buf = fmt.Appendf(buf, "Success:\t%t\n", res.Executions[0].VMState == vmstate.Halt)
} }
} }
if verbose { if verbose {
for _, sig := range tx.Signers { for _, sig := range tx.Signers {
_, _ = tw.Write([]byte(fmt.Sprintf("Signer:\t%s (%s)", buf = fmt.Appendf(buf, "Signer:\t%s (%s)\n", address.Uint160ToString(sig.Account), sig.Scopes)
address.Uint160ToString(sig.Account),
sig.Scopes) + "\n"))
} }
_, _ = tw.Write([]byte("SystemFee:\t" + fixedn.Fixed8(tx.SystemFee).String() + " GAS\n")) buf = fmt.Appendf(buf, "SystemFee:\t%s GAS\n", fixedn.Fixed8(tx.SystemFee).String())
_, _ = tw.Write([]byte("NetworkFee:\t" + fixedn.Fixed8(tx.NetworkFee).String() + " GAS\n")) buf = fmt.Appendf(buf, "NetworkFee:\t%s GAS\n", fixedn.Fixed8(tx.NetworkFee).String())
_, _ = tw.Write([]byte("Script:\t" + base64.StdEncoding.EncodeToString(tx.Script) + "\n")) buf = fmt.Appendf(buf, "Script:\t%s\n", base64.StdEncoding.EncodeToString(tx.Script))
v := vm.New() v := vm.New()
v.Load(tx.Script) v.Load(tx.Script)
v.PrintOps(tw) opts := bytes.NewBuffer(nil)
v.PrintOps(opts)
buf = append(buf, opts.Bytes()...)
if res != nil { if res != nil {
for _, e := range res.Executions { for _, e := range res.Executions {
if e.VMState != vmstate.Halt { if e.VMState != vmstate.Halt {
_, _ = tw.Write([]byte("Exception:\t" + e.FaultException + "\n")) buf = fmt.Appendf(buf, "Exception:\t%s\n", e.FaultException)
} }
} }
} }
} }
_ = tw.Flush() tw := tabwriter.NewWriter(ctx.App.Writer, 0, 4, 4, '\t', 0)
fmt.Fprint(ctx.App.Writer, buf.String()) _, err := tw.Write(buf)
if err != nil {
return err
}
return tw.Flush()
} }
func queryCandidates(ctx *cli.Context) error { func queryCandidates(ctx *cli.Context) error {
@ -196,15 +200,17 @@ func queryCandidates(ctx *cli.Context) error {
} }
return vals[i].PublicKey.Cmp(&vals[j].PublicKey) == -1 return vals[i].PublicKey.Cmp(&vals[j].PublicKey) == -1
}) })
buf := bytes.NewBuffer(nil) var res []byte
tw := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0) res = fmt.Appendf(res, "Key\tVotes\tCommittee\tConsensus\n")
_, _ = tw.Write([]byte("Key\tVotes\tCommittee\tConsensus\n"))
for _, val := range vals { for _, val := range vals {
_, _ = tw.Write([]byte(fmt.Sprintf("%s\t%d\t%t\t%t\n", hex.EncodeToString(val.PublicKey.Bytes()), val.Votes, comm.Contains(&val.PublicKey), val.Active))) res = fmt.Appendf(res, "%s\t%d\t%t\t%t\n", val.PublicKey.StringCompressed(), val.Votes, comm.Contains(&val.PublicKey), val.Active)
} }
_ = tw.Flush() tw := tabwriter.NewWriter(ctx.App.Writer, 0, 2, 2, ' ', 0)
fmt.Fprint(ctx.App.Writer, buf.String()) _, err = tw.Write(res)
return nil if err != nil {
return err
}
return tw.Flush()
} }
func queryCommittee(ctx *cli.Context) error { func queryCommittee(ctx *cli.Context) error {
@ -228,7 +234,7 @@ func queryCommittee(ctx *cli.Context) error {
} }
for _, k := range comm { for _, k := range comm {
fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(k.Bytes())) fmt.Fprintln(ctx.App.Writer, k.StringCompressed())
} }
return nil return nil
} }
@ -299,7 +305,7 @@ func queryVoter(ctx *cli.Context) error {
} }
voted := "null" voted := "null"
if st.VoteTo != nil { if st.VoteTo != nil {
voted = fmt.Sprintf("%s (%s)", hex.EncodeToString(st.VoteTo.Bytes()), address.Uint160ToString(st.VoteTo.GetScriptHash())) voted = fmt.Sprintf("%s (%s)", st.VoteTo.StringCompressed(), address.Uint160ToString(st.VoteTo.GetScriptHash()))
} }
fmt.Fprintf(ctx.App.Writer, "\tVoted: %s\n", voted) fmt.Fprintf(ctx.App.Writer, "\tVoted: %s\n", voted)
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", fixedn.ToString(&st.Balance, int(dec))) fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", fixedn.ToString(&st.Balance, int(dec)))

View file

@ -13,6 +13,9 @@ import (
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
// generated via `go run ./scripts/gendump/main.go --out ./cli/server/testdata/chain50x2.acc --blocks 50 --txs 2`.
const inDump = "./testdata/chain50x2.acc"
func TestDBRestoreDump(t *testing.T) { func TestDBRestoreDump(t *testing.T) {
tmpDir := t.TempDir() tmpDir := t.TempDir()
@ -32,8 +35,6 @@ func TestDBRestoreDump(t *testing.T) {
cfgPath := filepath.Join(tmpDir, "protocol.unit_testnet.yml") cfgPath := filepath.Join(tmpDir, "protocol.unit_testnet.yml")
require.NoError(t, os.WriteFile(cfgPath, out, os.ModePerm)) require.NoError(t, os.WriteFile(cfgPath, out, os.ModePerm))
// generated via `go run ./scripts/gendump/main.go --out ./cli/server/testdata/chain50x2.acc --blocks 50 --txs 2`
const inDump = "./testdata/chain50x2.acc"
e := testcli.NewExecutor(t, false) e := testcli.NewExecutor(t, false)
stateDump := filepath.Join(tmpDir, "neogo.teststate") stateDump := filepath.Join(tmpDir, "neogo.teststate")
@ -111,3 +112,47 @@ func TestDBRestoreDump(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, d1, d2, "dumps differ") require.Equal(t, d1, d2, "dumps differ")
} }
func TestDBDumpRestoreIncremental(t *testing.T) {
tmpDir := t.TempDir()
chainPath := filepath.Join(tmpDir, "neogotestchain")
nonincDump := filepath.Join(tmpDir, "nonincDump.acc")
incDump := filepath.Join(tmpDir, "incDump.acc")
cfg, err := config.LoadFile(filepath.Join("..", "..", "config", "protocol.unit_testnet.yml"))
require.NoError(t, err, "could not load config")
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath = chainPath
out, err := yaml.Marshal(cfg)
require.NoError(t, err)
cfgPath := filepath.Join(tmpDir, "protocol.unit_testnet.yml")
require.NoError(t, os.WriteFile(cfgPath, out, os.ModePerm))
e := testcli.NewExecutor(t, false)
// Create DB from dump.
e.Run(t, "neo-go", "db", "restore", "--unittest", "--config-path", tmpDir, "--in", inDump)
// Create two dumps: non-incremental and incremental.
dumpBaseArgs := []string{"neo-go", "db", "dump", "--unittest",
"--config-path", tmpDir}
// Dump first 15 blocks to a non-incremental dump.
e.Run(t, append(dumpBaseArgs, "--out", nonincDump, "--count", "15")...)
// Dump second 15 blocks to an incremental dump.
e.Run(t, append(dumpBaseArgs, "--out", incDump, "--start", "15", "--count", "15")...)
// Clean the DB.
require.NoError(t, os.RemoveAll(chainPath))
// Restore chain from two dumps.
restoreBaseArgs := []string{"neo-go", "db", "restore", "--unittest", "--config-path", tmpDir}
// Restore first 15 blocks from non-incremental dump.
e.Run(t, append(restoreBaseArgs, "--in", nonincDump)...)
// Restore second 15 blocks from incremental dump.
e.Run(t, append(restoreBaseArgs, "--in", incDump, "-n", "--count", "15")...)
}

View file

@ -77,7 +77,8 @@ func TestServerStart(t *testing.T) {
}) })
t.Run("invalid consensus config", func(t *testing.T) { t.Run("invalid consensus config", func(t *testing.T) {
saveCfg(t, func(cfg *config.Config) { saveCfg(t, func(cfg *config.Config) {
cfg.ApplicationConfiguration.UnlockWallet.Path = "bad_consensus_wallet.json" cfg.ApplicationConfiguration.Consensus.Enabled = true
cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path = "bad_consensus_wallet.json"
}) })
e.RunWithError(t, baseCmd...) e.RunWithError(t, baseCmd...)
}) })

View file

@ -34,7 +34,7 @@ import (
// NewCommands returns 'node' command. // NewCommands returns 'node' command.
func NewCommands() []cli.Command { func NewCommands() []cli.Command {
cfgFlags := []cli.Flag{options.Config} cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
cfgFlags = append(cfgFlags, options.Network...) cfgFlags = append(cfgFlags, options.Network...)
var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags)) var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags))
copy(cfgWithCountFlags, cfgFlags) copy(cfgWithCountFlags, cfgFlags)
@ -85,7 +85,7 @@ func NewCommands() []cli.Command {
{ {
Name: "node", Name: "node",
Usage: "start a NeoGo node", Usage: "start a NeoGo node",
UsageText: "neo-go node [--config-path path] [-d] [-p/-m/-t]", UsageText: "neo-go node [--config-path path] [-d] [-p/-m/-t] [--config-file file]",
Action: startServer, Action: startServer,
Flags: cfgFlags, Flags: cfgFlags,
}, },
@ -96,21 +96,21 @@ func NewCommands() []cli.Command {
{ {
Name: "dump", Name: "dump",
Usage: "dump blocks (starting with block #1) to the file", Usage: "dump blocks (starting with block #1) to the file",
UsageText: "neo-go db dump -o file [-s start] [-c count] [--config-path path] [-p/-m/-t]", UsageText: "neo-go db dump -o file [-s start] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]",
Action: dumpDB, Action: dumpDB,
Flags: cfgCountOutFlags, Flags: cfgCountOutFlags,
}, },
{ {
Name: "restore", Name: "restore",
Usage: "restore blocks from the file", Usage: "restore blocks from the file",
UsageText: "neo-go db restore -i file [--dump] [-n] [-c count] [--config-path path] [-p/-m/-t]", UsageText: "neo-go db restore -i file [--dump] [-n] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]",
Action: restoreDB, Action: restoreDB,
Flags: cfgCountInFlags, Flags: cfgCountInFlags,
}, },
{ {
Name: "reset", Name: "reset",
Usage: "reset database to the previous state", Usage: "reset database to the previous state",
UsageText: "neo-go db reset --height height [--config-path path] [-p/-m/-t]", UsageText: "neo-go db reset --height height [--config-path path] [-p/-m/-t] [--config-file file]",
Action: resetDB, Action: resetDB,
Flags: cfgHeightFlags, Flags: cfgHeightFlags,
}, },
@ -136,7 +136,6 @@ func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *m
if err != nil { if err != nil {
return nil, nil, nil, cli.NewExitError(err, 1) return nil, nil, nil, cli.NewExitError(err, 1)
} }
configureAddresses(&cfg.ApplicationConfiguration)
prometheus := metrics.NewPrometheusService(cfg.ApplicationConfiguration.Prometheus, log) prometheus := metrics.NewPrometheusService(cfg.ApplicationConfiguration.Prometheus, log)
pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, log) pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, log)
@ -198,6 +197,9 @@ func dumpDB(ctx *cli.Context) error {
if count == 0 { if count == 0 {
count = chainCount - start count = chainCount - start
} }
if start != 0 {
writer.WriteU32LE(start)
}
writer.WriteU32LE(count) writer.WriteU32LE(count)
err = chaindump.Dump(chain, writer, start, count) err = chaindump.Dump(chain, writer, start, count)
if err != nil { if err != nil {
@ -356,7 +358,14 @@ func resetDB(ctx *cli.Context) error {
return nil return nil
} }
func mkOracle(config config.OracleConfiguration, magic netmode.Magic, chain *core.Blockchain, serv *network.Server, log *zap.Logger) (*oracle.Oracle, error) { // oracleService is an interface representing Oracle service with network.Service
// capabilities and ability to submit oracle responses.
type oracleService interface {
rpcsrv.OracleHandler
network.Service
}
func mkOracle(config config.OracleConfiguration, magic netmode.Magic, chain *core.Blockchain, serv *network.Server, log *zap.Logger) (oracleService, error) {
if !config.Enabled { if !config.Enabled {
return nil, nil return nil, nil
} }
@ -413,7 +422,7 @@ func mkP2PNotary(config config.P2PNotary, chain *core.Blockchain, serv *network.
} }
n, err := notary.NewNotary(cfg, serv.Net, serv.GetNotaryPool(), func(tx *transaction.Transaction) error { n, err := notary.NewNotary(cfg, serv.Net, serv.GetNotaryPool(), func(tx *transaction.Transaction) error {
err := serv.RelayTxn(tx) err := serv.RelayTxn(tx)
if err != nil && !errors.Is(err, core.ErrAlreadyExists) { if err != nil && !errors.Is(err, core.ErrAlreadyExists) && !errors.Is(err, core.ErrAlreadyInPool) {
return fmt.Errorf("can't relay completed notary transaction: hash %s, error: %w", tx.Hash().StringLE(), err) return fmt.Errorf("can't relay completed notary transaction: hash %s, error: %w", tx.Hash().StringLE(), err)
} }
return nil return nil
@ -489,9 +498,12 @@ func startServer(ctx *cli.Context) error {
rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan) rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan)
serv.AddService(&rpcServer) serv.AddService(&rpcServer)
go serv.Start(errChan) serv.Start()
if !cfg.ApplicationConfiguration.RPC.StartWhenSynchronized { if !cfg.ApplicationConfiguration.RPC.StartWhenSynchronized {
rpcServer.Start() // Run RPC server in a separate routine. This is necessary to avoid a potential
// deadlock: Start() can write errors to errChan which is not yet read in the
// current execution context (see for-loop below).
go rpcServer.Start()
} }
sigCh := make(chan os.Signal, 1) sigCh := make(chan os.Signal, 1)
@ -534,7 +546,6 @@ Main:
break // Continue working. break // Continue working.
} }
} }
configureAddresses(&cfgnew.ApplicationConfiguration)
switch sig { switch sig {
case sighup: case sighup:
if newLogLevel != zapcore.InvalidLevel { if newLogLevel != zapcore.InvalidLevel {
@ -546,7 +557,8 @@ Main:
rpcServer = rpcsrv.New(chain, cfgnew.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan) rpcServer = rpcsrv.New(chain, cfgnew.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan)
serv.AddService(&rpcServer) serv.AddService(&rpcServer)
if !cfgnew.ApplicationConfiguration.RPC.StartWhenSynchronized || serv.IsInSync() { if !cfgnew.ApplicationConfiguration.RPC.StartWhenSynchronized || serv.IsInSync() {
rpcServer.Start() // Here similar to the initial run (see above for-loop), so async.
go rpcServer.Start()
} }
pprof.ShutDown() pprof.ShutDown()
pprof = metrics.NewPprofService(cfgnew.ApplicationConfiguration.Pprof, log) pprof = metrics.NewPprofService(cfgnew.ApplicationConfiguration.Pprof, log)
@ -634,24 +646,6 @@ Main:
return nil return nil
} }
// configureAddresses sets up addresses for RPC, Prometheus and Pprof depending from the provided config.
// In case RPC or Prometheus or Pprof Address provided each of them will use it.
// In case global Address (of the node) provided and RPC/Prometheus/Pprof don't have configured addresses they will
// use global one. So Node and RPC and Prometheus and Pprof will run on one address.
func configureAddresses(cfg *config.ApplicationConfiguration) {
if cfg.Address != nil && *cfg.Address != "" { //nolint:staticcheck // SA1019: cfg.Address is deprecated
if cfg.RPC.Address == nil || *cfg.RPC.Address == "" { //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
cfg.RPC.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
}
if cfg.Prometheus.Address == nil || *cfg.Prometheus.Address == "" { //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
cfg.Prometheus.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
}
if cfg.Pprof.Address == nil || *cfg.Pprof.Address == "" { //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
cfg.Pprof.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
}
}
}
// initBlockChain initializes BlockChain with preselected DB. // initBlockChain initializes BlockChain with preselected DB.
func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, storage.Store, error) { func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, storage.Store, error) {
store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration) store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration)

View file

@ -5,6 +5,7 @@ import (
"flag" "flag"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"testing" "testing"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
@ -30,13 +31,58 @@ func init() {
} }
func TestGetConfigFromContext(t *testing.T) { func TestGetConfigFromContext(t *testing.T) {
set := flag.NewFlagSet("flagSet", flag.ExitOnError) t.Run("config-path", func(t *testing.T) {
set.String("config-path", "../../config", "") set := flag.NewFlagSet("flagSet", flag.ExitOnError)
set.Bool("testnet", true, "") set.String("config-path", "../../config", "")
ctx := cli.NewContext(cli.NewApp(), set, nil) set.Bool("testnet", true, "")
cfg, err := options.GetConfigFromContext(ctx) ctx := cli.NewContext(cli.NewApp(), set, nil)
require.NoError(t, err) cfg, err := options.GetConfigFromContext(ctx)
require.Equal(t, netmode.TestNet, cfg.ProtocolConfiguration.Magic) require.NoError(t, err)
require.Equal(t, netmode.TestNet, cfg.ProtocolConfiguration.Magic)
})
t.Run("config-file", func(t *testing.T) {
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
set.String("config-path", "../../config", "")
set.Bool("testnet", true, "")
set.String("config-file", "../../config/protocol.testnet.yml", "")
ctx := cli.NewContext(cli.NewApp(), set, nil)
cfg, err := options.GetConfigFromContext(ctx)
require.NoError(t, err)
require.Equal(t, netmode.TestNet, cfg.ProtocolConfiguration.Magic)
})
t.Run("relative-path windows", func(t *testing.T) {
if runtime.GOOS != "windows" {
t.Skip("skipping Windows specific test")
}
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
set.String("relative-path", "..\\..\\config", "")
set.Bool("testnet", true, "")
set.String("config-file", ".\\testdata\\protocol.testnet.windows.yml", "")
ctx := cli.NewContext(cli.NewApp(), set, nil)
cfg, err := options.GetConfigFromContext(ctx)
require.NoError(t, err)
require.Equal(t, filepath.Join("..", "..", "config", "chains", "testnet"), cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath)
require.Equal(t, "C:\\someFolder\\cn_wallet.json", cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path)
require.Equal(t, "C:\\someFolder\\notary_wallet.json", cfg.ApplicationConfiguration.P2PNotary.UnlockWallet.Path)
})
t.Run("relative-path non-windows", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping non-Windows specific test")
}
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
set.String("relative-path", "../../config", "")
set.Bool("testnet", true, "")
set.String("config-file", "../../config/protocol.testnet.yml", "")
ctx := cli.NewContext(cli.NewApp(), set, nil)
cfg, err := options.GetConfigFromContext(ctx)
require.NoError(t, err)
require.Equal(t, filepath.Join("..", "..", "config", "chains", "testnet"), cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath)
require.Equal(t, "/cn_wallet.json", cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path)
require.Equal(t, "/notary_wallet.json", cfg.ApplicationConfiguration.P2PNotary.UnlockWallet.Path)
})
} }
func TestHandleLoggingParams(t *testing.T) { func TestHandleLoggingParams(t *testing.T) {
@ -312,64 +358,6 @@ func TestRestoreDB(t *testing.T) {
require.NoError(t, restoreDB(ctx)) require.NoError(t, restoreDB(ctx))
} }
// TestConfigureAddresses checks deprecated code compatibility, it should be removed
// along with deprecated `Address` field removal.
func TestConfigureAddresses(t *testing.T) {
defaultAddress := "http://localhost:10333"
customAddress := "http://localhost:10334"
t.Run("default addresses", func(t *testing.T) {
cfg := &config.ApplicationConfiguration{
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
}
configureAddresses(cfg)
require.Equal(t, defaultAddress, *cfg.RPC.Address) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
require.Equal(t, defaultAddress, *cfg.Prometheus.Address) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
require.Equal(t, defaultAddress, *cfg.Pprof.Address) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
})
t.Run("custom RPC address", func(t *testing.T) {
cfg := &config.ApplicationConfiguration{
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
RPC: config.RPC{
BasicService: config.BasicService{
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
},
},
}
configureAddresses(cfg)
require.Equal(t, *cfg.RPC.Address, customAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
require.Equal(t, *cfg.Prometheus.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
require.Equal(t, *cfg.Pprof.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
})
t.Run("custom Pprof address", func(t *testing.T) {
cfg := &config.ApplicationConfiguration{
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
Pprof: config.BasicService{
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
},
}
configureAddresses(cfg)
require.Equal(t, *cfg.RPC.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
require.Equal(t, *cfg.Prometheus.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
require.Equal(t, *cfg.Pprof.Address, customAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
})
t.Run("custom Prometheus address", func(t *testing.T) {
cfg := &config.ApplicationConfiguration{
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
Prometheus: config.BasicService{
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
},
}
configureAddresses(cfg)
require.Equal(t, *cfg.RPC.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
require.Equal(t, *cfg.Prometheus.Address, customAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
require.Equal(t, *cfg.Pprof.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
})
}
func TestInitBlockChain(t *testing.T) { func TestInitBlockChain(t *testing.T) {
t.Run("bad storage", func(t *testing.T) { t.Run("bad storage", func(t *testing.T) {
_, _, err := initBlockChain(config.Config{}, nil) _, _, err := initBlockChain(config.Config{}, nil)

View file

@ -0,0 +1,96 @@
ProtocolConfiguration:
Magic: 894710606
MaxBlockSize: 2097152
MaxBlockSystemFee: 150000000000
MaxTraceableBlocks: 2102400
MaxTransactionsPerBlock: 5000
InitialGASSupply: 52000000
TimePerBlock: 15s
MemPoolSize: 50000
StandbyCommittee:
- 023e9b32ea89b94d066e649b124fd50e396ee91369e8e2a6ae1b11c170d022256d
- 03009b7540e10f2562e5fd8fac9eaec25166a58b26e412348ff5a86927bfac22a2
- 02ba2c70f5996f357a43198705859fae2cfea13e1172962800772b3d588a9d4abd
- 03408dcd416396f64783ac587ea1e1593c57d9fea880c8a6a1920e92a259477806
- 02a7834be9b32e2981d157cb5bbd3acb42cfd11ea5c3b10224d7a44e98c5910f1b
- 0214baf0ceea3a66f17e7e1e839ea25fd8bed6cd82e6bb6e68250189065f44ff01
- 030205e9cefaea5a1dfc580af20c8d5aa2468bb0148f1a5e4605fc622c80e604ba
- 025831cee3708e87d78211bec0d1bfee9f4c85ae784762f042e7f31c0d40c329b8
- 02cf9dc6e85d581480d91e88e8cbeaa0c153a046e89ded08b4cefd851e1d7325b5
- 03840415b0a0fcf066bcc3dc92d8349ebd33a6ab1402ef649bae00e5d9f5840828
- 026328aae34f149853430f526ecaa9cf9c8d78a4ea82d08bdf63dd03c4d0693be6
- 02c69a8d084ee7319cfecf5161ff257aa2d1f53e79bf6c6f164cff5d94675c38b3
- 0207da870cedb777fceff948641021714ec815110ca111ccc7a54c168e065bda70
- 035056669864feea401d8c31e447fb82dd29f342a9476cfd449584ce2a6165e4d7
- 0370c75c54445565df62cfe2e76fbec4ba00d1298867972213530cae6d418da636
- 03957af9e77282ae3263544b7b2458903624adc3f5dee303957cb6570524a5f254
- 03d84d22b8753cf225d263a3a782a4e16ca72ef323cfde04977c74f14873ab1e4c
- 02147c1b1d5728e1954958daff2f88ee2fa50a06890a8a9db3fa9e972b66ae559f
- 03c609bea5a4825908027e4ab217e7efc06e311f19ecad9d417089f14927a173d5
- 0231edee3978d46c335e851c76059166eb8878516f459e085c0dd092f0f1d51c21
- 03184b018d6b2bc093e535519732b3fd3f7551c8cffaf4621dd5a0b89482ca66c9
ValidatorsCount: 7
SeedList:
- seed1t5.neo.org:20333
- seed2t5.neo.org:20333
- seed3t5.neo.org:20333
- seed4t5.neo.org:20333
- seed5t5.neo.org:20333
VerifyTransactions: false
P2PSigExtensions: false
Hardforks:
Aspidochelone: 210000
Basilisk: 2680000
ApplicationConfiguration:
SkipBlockVerification: false
DBConfiguration:
Type: "leveldb" #other options: 'inmemory','boltdb'
# DB type options. Uncomment those you need in case you want to switch DB type.
LevelDBOptions:
DataDirectoryPath: ".\\chains\\testnet"
P2P:
Addresses:
- ":20333" # in form of "[host]:[port][:announcedPort]"
DialTimeout: 3s
ProtoTickInterval: 2s
PingInterval: 30s
PingTimeout: 90s
MaxPeers: 100
AttemptConnPeers: 20
MinPeers: 10
Relay: true
Consensus:
Enabled: false
UnlockWallet:
Path: "C:\\someFolder\\cn_wallet.json"
Password: "pass"
Oracle:
Enabled: false
AllowedContentTypes:
- application/json
P2PNotary:
Enabled: false
UnlockWallet:
Path: "C:\\someFolder\\notary_wallet.json"
Password: "pass"
RPC:
Enabled: true
Addresses:
- ":20332"
MaxGasInvoke: 15
EnableCORSWorkaround: false
TLSConfig:
Enabled: false
Addresses:
- ":20331"
CertFile: serv.crt
KeyFile: serv.key
Prometheus:
Enabled: true
Addresses:
- ":2112"
Pprof:
Enabled: false
Addresses:
- ":2113"

View file

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
@ -13,6 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/cli/smartcontract" "github.com/nspcc-dev/neo-go/cli/smartcontract"
"github.com/nspcc-dev/neo-go/internal/random" "github.com/nspcc-dev/neo-go/internal/random"
"github.com/nspcc-dev/neo-go/internal/testcli" "github.com/nspcc-dev/neo-go/internal/testcli"
"github.com/nspcc-dev/neo-go/internal/versionutil"
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage" "github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
@ -23,6 +25,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate" "github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
@ -31,6 +34,9 @@ import (
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
// Keep contract NEFs consistent between runs.
const _ = versionutil.TestVersion
func TestCalcHash(t *testing.T) { func TestCalcHash(t *testing.T) {
tmpDir := t.TempDir() tmpDir := t.TempDir()
e := testcli.NewExecutor(t, false) e := testcli.NewExecutor(t, false)
@ -97,9 +103,6 @@ func TestCalcHash(t *testing.T) {
} }
func TestContractBindings(t *testing.T) { func TestContractBindings(t *testing.T) {
// For proper nef generation.
config.Version = "v0.98.1-test"
// For proper contract init. The actual version as it will be replaced. // For proper contract init. The actual version as it will be replaced.
smartcontract.ModVersion = "v0.0.0" smartcontract.ModVersion = "v0.0.0"
@ -143,18 +146,7 @@ func Blocks() []*alias.Block {
cmd = append(cmd, "--in", ctrPath, "--bindings", bindingsPath) cmd = append(cmd, "--in", ctrPath, "--bindings", bindingsPath)
// Replace `pkg/interop` in go.mod to avoid getting an actual module version. // Replace `pkg/interop` in go.mod to avoid getting an actual module version.
goMod := filepath.Join(ctrPath, "go.mod") require.NoError(t, updateGoMod(ctrPath, "myimport.com/testcontract", "../../pkg/interop"))
data, err := os.ReadFile(goMod)
require.NoError(t, err)
i := bytes.IndexByte(data, '\n')
data = append([]byte("module myimport.com/testcontract"), data[i:]...)
wd, err := os.Getwd()
require.NoError(t, err)
data = append(data, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "...)
data = append(data, filepath.Join(wd, "../../pkg/interop")...)
require.NoError(t, os.WriteFile(goMod, data, os.ModePerm))
cmd = append(cmd, "--config", cfgPath, cmd = append(cmd, "--config", cfgPath,
"--out", filepath.Join(tmpDir, "out.nef"), "--out", filepath.Join(tmpDir, "out.nef"),
@ -174,7 +166,9 @@ func Blocks() []*alias.Block {
bs, err := os.ReadFile(outPath) bs, err := os.ReadFile(outPath)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, `// Package testcontract contains wrappers for testcontract contract. require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package testcontract contains wrappers for testcontract contract.
package testcontract package testcontract
import ( import (
@ -209,10 +203,85 @@ func ToMap(a []testcontract.MyPair) map[int]string {
`, string(bs)) `, string(bs))
} }
func TestContractInitAndCompile(t *testing.T) { // updateGoMod updates the go.mod file located in the specified directory.
// For proper nef generation. // It sets the module name and replaces the neo-go interop package path with
config.Version = "v0.98.1-test" // the provided one to avoid getting an actual module version.
func updateGoMod(dir, moduleName, neoGoPath string) error {
goModPath := filepath.Join(dir, "go.mod")
data, err := os.ReadFile(goModPath)
if err != nil {
return fmt.Errorf("failed to read go.mod: %w", err)
}
i := bytes.IndexByte(data, '\n')
if i == -1 {
return fmt.Errorf("unexpected go.mod format")
}
updatedData := append([]byte("module "+moduleName), data[i:]...)
wd, err := os.Getwd()
if err != nil {
return fmt.Errorf("failed to get working directory: %w", err)
}
replacementPath := filepath.Join(wd, neoGoPath)
updatedData = append(updatedData, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "+replacementPath+" \n"...)
if err := os.WriteFile(goModPath, updatedData, os.ModePerm); err != nil {
return fmt.Errorf("failed to write updated go.mod: %w", err)
}
return nil
}
func TestDynamicWrapper(t *testing.T) {
// For proper contract init. The actual version as it will be replaced.
smartcontract.ModVersion = "v0.0.0"
tmpDir := t.TempDir()
e := testcli.NewExecutor(t, true)
ctrPath := "../smartcontract/testdata"
verifyHash := testcli.DeployContract(t, e, filepath.Join(ctrPath, "verify.go"), filepath.Join(ctrPath, "verify.yml"), testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
helperContract := `package testcontract
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
verify "myimport.com/testcontract/bindings"
)
func CallVerifyContract(h interop.Hash160) bool{
contractInstance := verify.NewContract(h)
return contractInstance.Verify()
}`
helperDir := filepath.Join(tmpDir, "helper")
e.Run(t, "neo-go", "contract", "init", "--name", helperDir)
require.NoError(t, updateGoMod(helperDir, "myimport.com/testcontract", "../../pkg/interop"))
require.NoError(t, os.WriteFile(filepath.Join(helperDir, "main.go"), []byte(helperContract), os.ModePerm))
require.NoError(t, os.Mkdir(filepath.Join(helperDir, "bindings"), os.ModePerm))
e.Run(t, "neo-go", "contract", "generate-wrapper",
"--config", filepath.Join(ctrPath, "verify.bindings.yml"), "--manifest", filepath.Join(ctrPath, "verify.manifest.json"),
"--out", filepath.Join(helperDir, "bindings", "testdata.go"))
e.Run(t, "neo-go", "contract", "compile", "--in", filepath.Join(helperDir, "main.go"), "--config", filepath.Join(helperDir, "neo-go.yml"))
helperHash := testcli.DeployContract(t, e, filepath.Join(helperDir, "main.go"), filepath.Join(helperDir, "neo-go.yml"), testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
e.In.WriteString("one\r")
e.Run(t, "neo-go", "contract", "invokefunction",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--force", "--await", helperHash.StringLE(), "callVerifyContract", verifyHash.StringLE())
tx, _ := e.CheckTxPersisted(t, "Sent invocation transaction ")
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
require.NoError(t, err)
require.Equal(t, aer[0].Stack[0].Value().(bool), true)
}
func TestContractInitAndCompile(t *testing.T) {
// For proper contract init. The actual version as it will be replaced. // For proper contract init. The actual version as it will be replaced.
smartcontract.ModVersion = "v0.0.0" smartcontract.ModVersion = "v0.0.0"
@ -237,7 +306,8 @@ func TestContractInitAndCompile(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "init", "--name", ctrPath) e.RunWithError(t, "neo-go", "contract", "init", "--name", ctrPath)
}) })
srcPath := filepath.Join(ctrPath, "main.go") ctrRootPath := filepath.Join(ctrPath, "main")
srcPath := ctrRootPath + ".go"
cfgPath := filepath.Join(ctrPath, "neo-go.yml") cfgPath := filepath.Join(ctrPath, "neo-go.yml")
nefPath := filepath.Join(tmpDir, "testcontract.nef") nefPath := filepath.Join(tmpDir, "testcontract.nef")
manifestPath := filepath.Join(tmpDir, "testcontract.manifest.json") manifestPath := filepath.Join(tmpDir, "testcontract.manifest.json")
@ -263,15 +333,7 @@ func TestContractInitAndCompile(t *testing.T) {
}) })
// Replace `pkg/interop` in go.mod to avoid getting an actual module version. // Replace `pkg/interop` in go.mod to avoid getting an actual module version.
goMod := filepath.Join(ctrPath, "go.mod") require.NoError(t, updateGoMod(ctrPath, "myimport.com/testcontract", "../../pkg/interop"))
data, err := os.ReadFile(goMod)
require.NoError(t, err)
wd, err := os.Getwd()
require.NoError(t, err)
data = append(data, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "...)
data = append(data, filepath.Join(wd, "../../pkg/interop")...)
require.NoError(t, os.WriteFile(goMod, data, os.ModePerm))
cmd = append(cmd, "--config", cfgPath) cmd = append(cmd, "--config", cfgPath)
@ -288,6 +350,19 @@ func TestContractInitAndCompile(t *testing.T) {
e.Run(t, append(cmd, "--verbose")...) e.Run(t, append(cmd, "--verbose")...)
e.CheckNextLine(t, "^[0-9a-hA-H]+$") e.CheckNextLine(t, "^[0-9a-hA-H]+$")
}) })
t.Run("autocomplete outputs", func(t *testing.T) {
cfg, err := os.ReadFile(cfgPath)
require.NoError(t, err)
require.NoError(t, os.WriteFile(filepath.Join(ctrPath, "main.yml"), cfg, os.ModePerm))
e.Run(t, "neo-go", "contract", "compile", "--in", srcPath)
defaultNefPath := ctrRootPath + ".nef"
defaultManifestPath := ctrRootPath + ".manifest.json"
defaultBindingsPath := ctrRootPath + ".bindings.yml"
require.FileExists(t, defaultNefPath)
require.FileExists(t, defaultManifestPath)
require.FileExists(t, defaultBindingsPath)
})
} }
// Checks that error is returned if GAS available for test-invoke exceeds // Checks that error is returned if GAS available for test-invoke exceeds
@ -296,9 +371,6 @@ func TestDeployBigContract(t *testing.T) {
e := testcli.NewExecutorWithConfig(t, true, true, func(c *config.Config) { e := testcli.NewExecutorWithConfig(t, true, true, func(c *config.Config) {
c.ApplicationConfiguration.RPC.MaxGasInvoke = fixedn.Fixed8(1) c.ApplicationConfiguration.RPC.MaxGasInvoke = fixedn.Fixed8(1)
}) })
// For proper nef generation.
config.Version = "0.90.0-test"
tmpDir := t.TempDir() tmpDir := t.TempDir()
nefName := filepath.Join(tmpDir, "deploy.nef") nefName := filepath.Join(tmpDir, "deploy.nef")
@ -317,9 +389,6 @@ func TestDeployBigContract(t *testing.T) {
func TestContractDeployWithData(t *testing.T) { func TestContractDeployWithData(t *testing.T) {
eCompile := testcli.NewExecutor(t, false) eCompile := testcli.NewExecutor(t, false)
// For proper nef generation.
config.Version = "0.90.0-test"
tmpDir := t.TempDir() tmpDir := t.TempDir()
nefName := filepath.Join(tmpDir, "deploy.nef") nefName := filepath.Join(tmpDir, "deploy.nef")
@ -329,7 +398,7 @@ func TestContractDeployWithData(t *testing.T) {
"--config", "testdata/deploy/neo-go.yml", "--config", "testdata/deploy/neo-go.yml",
"--out", nefName, "--manifest", manifestName) "--out", nefName, "--manifest", manifestName)
deployContract := func(t *testing.T, haveData bool, scope string) { deployContract := func(t *testing.T, haveData bool, scope string, await bool) {
e := testcli.NewExecutor(t, true) e := testcli.NewExecutor(t, true)
cmd := []string{ cmd := []string{
"neo-go", "contract", "deploy", "neo-go", "contract", "deploy",
@ -339,6 +408,9 @@ func TestContractDeployWithData(t *testing.T) {
"--force", "--force",
} }
if await {
cmd = append(cmd, "--await")
}
if haveData { if haveData {
cmd = append(cmd, "[", "key1", "12", "key2", "take_me_to_church", "]") cmd = append(cmd, "[", "key1", "12", "key2", "take_me_to_church", "]")
} }
@ -349,8 +421,13 @@ func TestContractDeployWithData(t *testing.T) {
} }
e.In.WriteString(testcli.ValidatorPass + "\r") e.In.WriteString(testcli.ValidatorPass + "\r")
e.Run(t, cmd...) e.Run(t, cmd...)
var tx *transaction.Transaction
if await {
tx, _ = e.CheckAwaitableTxPersisted(t)
} else {
tx, _ = e.CheckTxPersisted(t)
}
tx, _ := e.CheckTxPersisted(t, "Sent invocation transaction ")
require.Equal(t, scope, tx.Signers[0].Scopes.String()) require.Equal(t, scope, tx.Signers[0].Scopes.String())
if !haveData { if !haveData {
return return
@ -387,16 +464,16 @@ func TestContractDeployWithData(t *testing.T) {
require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value()) require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value())
} }
deployContract(t, true, "") deployContract(t, true, "", false)
deployContract(t, false, "Global") deployContract(t, false, "Global", false)
deployContract(t, true, "Global") deployContract(t, true, "Global", false)
deployContract(t, false, "", true)
deployContract(t, true, "Global", true)
deployContract(t, true, "", true)
} }
func TestDeployWithSigners(t *testing.T) { func TestDeployWithSigners(t *testing.T) {
e := testcli.NewExecutor(t, true) e := testcli.NewExecutor(t, true)
// For proper nef generation.
config.Version = "0.90.0-test"
tmpDir := t.TempDir() tmpDir := t.TempDir()
nefName := filepath.Join(tmpDir, "deploy.nef") nefName := filepath.Join(tmpDir, "deploy.nef")
@ -458,9 +535,6 @@ func TestDeployWithSigners(t *testing.T) {
func TestContractManifestGroups(t *testing.T) { func TestContractManifestGroups(t *testing.T) {
e := testcli.NewExecutor(t, true) e := testcli.NewExecutor(t, true)
// For proper nef generation.
config.Version = "0.90.0-test"
tmpDir := t.TempDir() tmpDir := t.TempDir()
_, err := wallet.NewWalletFromFile(testcli.TestWalletPath) _, err := wallet.NewWalletFromFile(testcli.TestWalletPath)
@ -617,9 +691,6 @@ func TestContract_TestInvokeScript(t *testing.T) {
func TestComlileAndInvokeFunction(t *testing.T) { func TestComlileAndInvokeFunction(t *testing.T) {
e := testcli.NewExecutor(t, true) e := testcli.NewExecutor(t, true)
// For proper nef generation.
config.Version = "0.90.0-test"
tmpDir := t.TempDir() tmpDir := t.TempDir()
nefName := filepath.Join(tmpDir, "deploy.nef") nefName := filepath.Join(tmpDir, "deploy.nef")
@ -772,6 +843,12 @@ func TestComlileAndInvokeFunction(t *testing.T) {
e.Run(t, append(cmd, h.StringLE(), "getValue", e.Run(t, append(cmd, h.StringLE(), "getValue",
"--", testcli.ValidatorAddr, hVerify.StringLE())...) "--", testcli.ValidatorAddr, hVerify.StringLE())...)
}) })
t.Run("with await", func(t *testing.T) {
e.In.WriteString("one\r")
e.Run(t, append(cmd, "--force", "--await", h.StringLE(), "getValue")...)
e.CheckAwaitableTxPersisted(t)
})
}) })
t.Run("real invoke and save tx", func(t *testing.T) { t.Run("real invoke and save tx", func(t *testing.T) {
@ -949,9 +1026,6 @@ func TestComlileAndInvokeFunction(t *testing.T) {
func TestContractInspect(t *testing.T) { func TestContractInspect(t *testing.T) {
e := testcli.NewExecutor(t, false) e := testcli.NewExecutor(t, false)
// For proper nef generation.
config.Version = "0.90.0-test"
const srcPath = "testdata/deploy/main.go" const srcPath = "testdata/deploy/main.go"
tmpDir := t.TempDir() tmpDir := t.TempDir()
@ -986,9 +1060,6 @@ func TestCompileExamples(t *testing.T) {
infos, err := os.ReadDir(examplePath) infos, err := os.ReadDir(examplePath)
require.NoError(t, err) require.NoError(t, err)
// For proper nef generation.
config.Version = "0.90.0-test"
e := testcli.NewExecutor(t, false) e := testcli.NewExecutor(t, false)
for _, info := range infos { for _, info := range infos {
@ -997,6 +1068,10 @@ func TestCompileExamples(t *testing.T) {
// there are also a couple of files inside the `/examples` which doesn't need to be compiled // there are also a couple of files inside the `/examples` which doesn't need to be compiled
continue continue
} }
if info.Name() == "zkp" {
// A set of special ZKP-related examples, they have their own tests.
continue
}
t.Run(info.Name(), func(t *testing.T) { t.Run(info.Name(), func(t *testing.T) {
infos, err := os.ReadDir(filepath.Join(examplePath, info.Name())) infos, err := os.ReadDir(filepath.Join(examplePath, info.Name()))
require.NoError(t, err) require.NoError(t, err)
@ -1073,3 +1148,27 @@ func filterFilename(infos []os.DirEntry, ext string) string {
} }
return "" return ""
} }
func TestContractCompile_NEFSizeCheck(t *testing.T) {
tmpDir := t.TempDir()
e := testcli.NewExecutor(t, false)
src := `package nefconstraints
var data = "%s"
func Main() string {
return data
}`
data := make([]byte, stackitem.MaxSize-10)
for i := range data {
data[i] = byte('a')
}
in := filepath.Join(tmpDir, "main.go")
cfg := filepath.Join(tmpDir, "main.yml")
require.NoError(t, os.WriteFile(cfg, []byte("name: main"), os.ModePerm))
require.NoError(t, os.WriteFile(in, []byte(fmt.Sprintf(src, data)), os.ModePerm))
e.RunWithError(t, "neo-go", "contract", "compile", "--in", in)
require.NoFileExists(t, filepath.Join(tmpDir, "main.nef"))
}

View file

@ -29,25 +29,29 @@ var generatorFlags = []cli.Flag{
Usage: "Output of the compiled wrapper", Usage: "Output of the compiled wrapper",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "hash", Name: "hash",
Required: true, Usage: "Smart-contract hash. If not passed, the wrapper will be designed for dynamic hash usage",
Usage: "Smart-contract hash",
}, },
} }
var generateWrapperCmd = cli.Command{ var generateWrapperCmd = cli.Command{
Name: "generate-wrapper", Name: "generate-wrapper",
Usage: "generate wrapper to use in other contracts", Usage: "generate wrapper to use in other contracts",
UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> --hash <hash> [--config <config>]", UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
Description: ``, Description: `Generates a Go wrapper to use it in other smart contracts. If the
Action: contractGenerateWrapper, --hash flag is provided, CALLT instruction is used for the target contract
Flags: generatorFlags, invocation as an optimization of the wrapper contract code. If omitted, the
generated wrapper will be designed for dynamic hash usage, allowing
the hash to be specified at runtime.
`,
Action: contractGenerateWrapper,
Flags: generatorFlags,
} }
var generateRPCWrapperCmd = cli.Command{ var generateRPCWrapperCmd = cli.Command{
Name: "generate-rpcwrapper", Name: "generate-rpcwrapper",
Usage: "generate RPC wrapper to use for data reads", Usage: "generate RPC wrapper to use for data reads",
UsageText: "neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> --hash <hash> [--config <config>]", UsageText: "neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
Action: contractGenerateRPCWrapper, Action: contractGenerateRPCWrapper,
Flags: generatorFlags, Flags: generatorFlags,
} }
@ -65,9 +69,15 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error)
if err := cmdargs.EnsureNone(ctx); err != nil { if err := cmdargs.EnsureNone(ctx); err != nil {
return err return err
} }
h, err := util.Uint160DecodeStringLE(strings.TrimPrefix(ctx.String("hash"), "0x")) var (
if err != nil { h util.Uint160
return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1) err error
)
if hStr := ctx.String("hash"); len(hStr) != 0 {
h, err = util.Uint160DecodeStringLE(strings.TrimPrefix(hStr, "0x"))
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1)
}
} }
m, _, err := readManifest(ctx.String("manifest"), h) m, _, err := readManifest(ctx.String("manifest"), h)
if err != nil { if err != nil {

View file

@ -3,6 +3,7 @@ package smartcontract
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -150,7 +151,9 @@ callflags:
"--hash", h.StringLE(), "--hash", h.StringLE(),
})) }))
const expected = `// Package wrapper contains wrappers for MyContract contract. const expected = `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package wrapper contains wrappers for MyContract contract.
package wrapper package wrapper
import ( import (
@ -171,8 +174,8 @@ func Sum(first int, second int) int {
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second).(int) return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second).(int)
} }
// Sum_3 invokes ` + "`sum`" + ` method of contract. // Sum2 invokes ` + "`sum`" + ` method of contract.
func Sum_3(first int, second int, third int) int { func Sum2(first int, second int, third int) int {
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second, third).(int) return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second, third).(int)
} }
@ -230,6 +233,99 @@ func MyFunc(in map[int]mycontract.Input) []mycontract.Output {
data, err := os.ReadFile(outFile) data, err := os.ReadFile(outFile)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, expected, string(data)) require.Equal(t, expected, string(data))
require.NoError(t, app.Run([]string{"", "generate-wrapper",
"--manifest", manifestFile,
"--config", cfgPath,
"--out", outFile,
}))
expectedWithDynamicHash := `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package wrapper contains wrappers for MyContract contract.
package wrapper
import (
"github.com/heyitsme/mycontract"
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
)
// Contract represents the MyContract smart contract.
type Contract struct {
Hash interop.Hash160
}
// NewContract returns a new Contract instance with the specified hash.
func NewContract(hash interop.Hash160) Contract {
return Contract{Hash: hash}
}
// Sum invokes ` + "`sum`" + ` method of contract.
func (c Contract) Sum(first int, second int) int {
return contract.Call(c.Hash, "sum", contract.All, first, second).(int)
}
// Sum2 invokes ` + "`sum`" + ` method of contract.
func (c Contract) Sum2(first int, second int, third int) int {
return contract.Call(c.Hash, "sum", contract.All, first, second, third).(int)
}
// Sum3 invokes ` + "`sum3`" + ` method of contract.
func (c Contract) Sum3() int {
return contract.Call(c.Hash, "sum3", contract.ReadOnly).(int)
}
// Zum invokes ` + "`zum`" + ` method of contract.
func (c Contract) Zum(typev int, typev_ int, funcv int) int {
return contract.Call(c.Hash, "zum", contract.All, typev, typev_, funcv).(int)
}
// JustExecute invokes ` + "`justExecute`" + ` method of contract.
func (c Contract) JustExecute(arr []any) {
contract.Call(c.Hash, "justExecute", contract.All, arr)
}
// GetPublicKey invokes ` + "`getPublicKey`" + ` method of contract.
func (c Contract) GetPublicKey() interop.PublicKey {
return contract.Call(c.Hash, "getPublicKey", contract.All).(interop.PublicKey)
}
// OtherTypes invokes ` + "`otherTypes`" + ` method of contract.
func (c Contract) OtherTypes(ctr interop.Hash160, tx interop.Hash256, sig interop.Signature, data any) bool {
return contract.Call(c.Hash, "otherTypes", contract.All, ctr, tx, sig, data).(bool)
}
// SearchStorage invokes ` + "`searchStorage`" + ` method of contract.
func (c Contract) SearchStorage(ctx storage.Context) iterator.Iterator {
return contract.Call(c.Hash, "searchStorage", contract.All, ctx).(iterator.Iterator)
}
// GetFromMap invokes ` + "`getFromMap`" + ` method of contract.
func (c Contract) GetFromMap(intMap map[string]int, indices []string) []int {
return contract.Call(c.Hash, "getFromMap", contract.All, intMap, indices).([]int)
}
// DoSomething invokes ` + "`doSomething`" + ` method of contract.
func (c Contract) DoSomething(bytes []byte, str string) any {
return contract.Call(c.Hash, "doSomething", contract.ReadStates, bytes, str).(any)
}
// GetBlockWrapper invokes ` + "`getBlockWrapper`" + ` method of contract.
func (c Contract) GetBlockWrapper() ledger.Block {
return contract.Call(c.Hash, "getBlockWrapper", contract.All).(ledger.Block)
}
// MyFunc invokes ` + "`myFunc`" + ` method of contract.
func (c Contract) MyFunc(in map[int]mycontract.Input) []mycontract.Output {
return contract.Call(c.Hash, "myFunc", contract.All, in).([]mycontract.Output)
}
`
data, err = os.ReadFile(outFile)
require.NoError(t, err)
require.Equal(t, expectedWithDynamicHash, string(data))
} }
func TestGenerateValidPackageName(t *testing.T) { func TestGenerateValidPackageName(t *testing.T) {
@ -264,7 +360,9 @@ func TestGenerateValidPackageName(t *testing.T) {
data, err := os.ReadFile(outFile) data, err := os.ReadFile(outFile)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, `// Package myspacecontract contains wrappers for My space contract contract. require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package myspacecontract contains wrappers for My space contract contract.
package myspacecontract package myspacecontract
import ( import (
@ -288,7 +386,9 @@ func Get() int {
data, err = os.ReadFile(outFile) data, err = os.ReadFile(outFile)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, `// Package myspacecontract contains RPC wrappers for My space contract contract. require.Equal(t, `// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package myspacecontract contains RPC wrappers for My space contract contract.
package myspacecontract package myspacecontract
import ( import (
@ -309,21 +409,26 @@ type Invoker interface {
// ContractReader implements safe contract methods. // ContractReader implements safe contract methods.
type ContractReader struct { type ContractReader struct {
invoker Invoker invoker Invoker
hash util.Uint160
} }
// NewReader creates an instance of ContractReader using Hash and the given Invoker. // NewReader creates an instance of ContractReader using Hash and the given Invoker.
func NewReader(invoker Invoker) *ContractReader { func NewReader(invoker Invoker) *ContractReader {
return &ContractReader{invoker} var hash = Hash
return &ContractReader{invoker, hash}
} }
// Get invokes `+"`get`"+` method of contract. // Get invokes `+"`get`"+` method of contract.
func (c *ContractReader) Get() (*big.Int, error) { func (c *ContractReader) Get() (*big.Int, error) {
return unwrap.BigInt(c.invoker.Call(Hash, "get")) return unwrap.BigInt(c.invoker.Call(c.hash, "get"))
} }
`, string(data)) `, string(data))
} }
// rewriteExpectedOutputs denotes whether expected output files should be rewritten
// for TestGenerateRPCBindings and TestAssistedRPCBindings.
const rewriteExpectedOutputs = false
func TestGenerateRPCBindings(t *testing.T) { func TestGenerateRPCBindings(t *testing.T) {
tmpDir := t.TempDir() tmpDir := t.TempDir()
app := cli.NewApp() app := cli.NewApp()
@ -341,10 +446,14 @@ func TestGenerateRPCBindings(t *testing.T) {
data, err := os.ReadFile(outFile) data, err := os.ReadFile(outFile)
require.NoError(t, err) require.NoError(t, err)
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows. data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
expected, err := os.ReadFile(good) if rewriteExpectedOutputs {
require.NoError(t, err) require.NoError(t, os.WriteFile(good, data, os.ModePerm))
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows. } else {
require.Equal(t, string(expected), string(data)) expected, err := os.ReadFile(good)
require.NoError(t, err)
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows.
require.Equal(t, string(expected), string(data))
}
}) })
} }
@ -363,6 +472,8 @@ func TestGenerateRPCBindings(t *testing.T) {
checkBinding(filepath.Join("testdata", "nonepiter", "iter.manifest.json"), checkBinding(filepath.Join("testdata", "nonepiter", "iter.manifest.json"),
"0x00112233445566778899aabbccddeeff00112233", "0x00112233445566778899aabbccddeeff00112233",
filepath.Join("testdata", "nonepiter", "iter.go")) filepath.Join("testdata", "nonepiter", "iter.go"))
require.False(t, rewriteExpectedOutputs)
} }
func TestAssistedRPCBindings(t *testing.T) { func TestAssistedRPCBindings(t *testing.T) {
@ -370,38 +481,70 @@ func TestAssistedRPCBindings(t *testing.T) {
app := cli.NewApp() app := cli.NewApp()
app.Commands = NewCommands() app.Commands = NewCommands()
var checkBinding = func(source string) { var checkBinding = func(source string, hasDefinedHash bool, guessEventTypes bool, suffix ...string) {
t.Run(source, func(t *testing.T) { testName := source
if len(suffix) != 0 {
testName += suffix[0]
}
testName += fmt.Sprintf(", predefined hash: %t", hasDefinedHash)
t.Run(testName, func(t *testing.T) {
outFile := filepath.Join(tmpDir, "out.go")
configFile := filepath.Join(source, "config.yml")
expectedFile := filepath.Join(source, "rpcbindings.out")
if len(suffix) != 0 {
configFile = filepath.Join(source, "config"+suffix[0]+".yml")
expectedFile = filepath.Join(source, "rpcbindings"+suffix[0]+".out")
} else if !hasDefinedHash {
expectedFile = filepath.Join(source, "rpcbindings_dynamic_hash.out")
}
manifestF := filepath.Join(tmpDir, "manifest.json") manifestF := filepath.Join(tmpDir, "manifest.json")
bindingF := filepath.Join(tmpDir, "binding.yml") bindingF := filepath.Join(tmpDir, "binding.yml")
nefF := filepath.Join(tmpDir, "out.nef") nefF := filepath.Join(tmpDir, "out.nef")
require.NoError(t, app.Run([]string{"", "contract", "compile", cmd := []string{"", "contract", "compile",
"--in", source, "--in", source,
"--config", filepath.Join(source, "config.yml"), "--config", configFile,
"--manifest", manifestF, "--manifest", manifestF,
"--bindings", bindingF, "--bindings", bindingF,
"--out", nefF, "--out", nefF,
})) }
outFile := filepath.Join(tmpDir, "out.go") if guessEventTypes {
require.NoError(t, app.Run([]string{"", "contract", "generate-rpcwrapper", cmd = append(cmd, "--guess-eventtypes")
}
require.NoError(t, app.Run(cmd))
cmds := []string{"", "contract", "generate-rpcwrapper",
"--config", bindingF, "--config", bindingF,
"--manifest", manifestF, "--manifest", manifestF,
"--out", outFile, "--out", outFile,
"--hash", "0x00112233445566778899aabbccddeeff00112233", }
})) if hasDefinedHash {
cmds = append(cmds, "--hash", "0x00112233445566778899aabbccddeeff00112233")
}
require.NoError(t, app.Run(cmds))
data, err := os.ReadFile(outFile) data, err := os.ReadFile(outFile)
require.NoError(t, err) require.NoError(t, err)
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows. data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
expected, err := os.ReadFile(filepath.Join(source, "rpcbindings.out")) if rewriteExpectedOutputs {
require.NoError(t, err) require.NoError(t, os.WriteFile(expectedFile, data, os.ModePerm))
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows. } else {
require.Equal(t, string(expected), string(data)) expected, err := os.ReadFile(expectedFile)
require.NoError(t, err)
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows.
require.Equal(t, string(expected), string(data))
}
}) })
} }
checkBinding(filepath.Join("testdata", "types")) for _, hasDefinedHash := range []bool{true, false} {
checkBinding(filepath.Join("testdata", "structs")) checkBinding(filepath.Join("testdata", "rpcbindings", "types"), hasDefinedHash, false)
checkBinding(filepath.Join("testdata", "rpcbindings", "structs"), hasDefinedHash, false)
}
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, false)
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, false, "_extended")
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, true, "_guessed")
require.False(t, rewriteExpectedOutputs)
} }
func TestGenerate_Errors(t *testing.T) { func TestGenerate_Errors(t *testing.T) {
@ -467,3 +610,103 @@ callflags:
"--config", cfgPath, "--out", "zzz") "--config", cfgPath, "--out", "zzz")
}) })
} }
func TestCompile_GuessEventTypes(t *testing.T) {
app := cli.NewApp()
app.Commands = NewCommands()
app.ExitErrHandler = func(*cli.Context, error) {}
checkError := func(t *testing.T, msg string, args ...string) {
// cli.ExitError doesn't implement wraping properly, so we check for an error message.
err := app.Run(args)
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), msg), "got: %v", err)
}
check := func(t *testing.T, source string, expectedErrText string) {
tmpDir := t.TempDir()
configFile := filepath.Join(source, "invalid.yml")
manifestF := filepath.Join(tmpDir, "invalid.manifest.json")
bindingF := filepath.Join(tmpDir, "invalid.binding.yml")
nefF := filepath.Join(tmpDir, "invalid.out.nef")
cmd := []string{"", "contract", "compile",
"--in", source,
"--config", configFile,
"--manifest", manifestF,
"--bindings", bindingF,
"--out", nefF,
"--guess-eventtypes",
}
checkError(t, expectedErrText, cmd...)
}
t.Run("not declared in manifest", func(t *testing.T) {
check(t, filepath.Join("testdata", "rpcbindings", "invalid1"), "inconsistent usages of event `Non declared event`: not declared in the contract config")
})
t.Run("invalid number of params", func(t *testing.T) {
check(t, filepath.Join("testdata", "rpcbindings", "invalid2"), "inconsistent usages of event `SomeEvent` against config: number of params mismatch: 2 vs 1")
})
/*
// TODO: this on is a controversial one. If event information is provided in the config file, then conversion code
// will be emitted by the compiler according to the parameter type provided via config. Thus, we can be sure that
// either event parameter has the type specified in the config file or the execution of the contract will fail.
// Thus, this testcase is always failing (no compilation error occures).
// Question: do we want to compare `RealType` of the emitted parameter with the one expected in the manifest?
t.Run("SC parameter type mismatch", func(t *testing.T) {
check(t, filepath.Join("testdata", "rpcbindings", "invalid3"), "inconsistent usages of event `SomeEvent` against config: number of params mismatch: 2 vs 1")
})
*/
t.Run("extended types mismatch", func(t *testing.T) {
check(t, filepath.Join("testdata", "rpcbindings", "invalid4"), "inconsistent usages of event `SomeEvent`: extended type of param #0 mismatch")
})
t.Run("named types redeclare", func(t *testing.T) {
check(t, filepath.Join("testdata", "rpcbindings", "invalid5"), "configured declared named type intersects with the contract's one: `invalid5.NamedStruct`")
})
}
func TestGenerateRPCBindings_Errors(t *testing.T) {
app := cli.NewApp()
app.Commands = NewCommands()
app.ExitErrHandler = func(*cli.Context, error) {}
t.Run("duplicating resulting fields", func(t *testing.T) {
check := func(t *testing.T, packageName string, autogen bool, expectedError string) {
tmpDir := t.TempDir()
source := filepath.Join("testdata", "rpcbindings", packageName)
configFile := filepath.Join(source, "invalid.yml")
out := filepath.Join(tmpDir, "rpcbindings.out")
manifestF := filepath.Join(tmpDir, "manifest.json")
bindingF := filepath.Join(tmpDir, "binding.yml")
nefF := filepath.Join(tmpDir, "out.nef")
cmd := []string{"", "contract", "compile",
"--in", source,
"--config", configFile,
"--manifest", manifestF,
"--bindings", bindingF,
"--out", nefF,
}
if autogen {
cmd = append(cmd, "--guess-eventtypes")
}
require.NoError(t, app.Run(cmd))
cmds := []string{"", "contract", "generate-rpcwrapper",
"--config", bindingF,
"--manifest", manifestF,
"--out", out,
}
err := app.Run(cmds)
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), expectedError), err.Error())
}
t.Run("event", func(t *testing.T) {
check(t, "invalid6", false, "error during generation: named type `SomeStruct` has two fields with identical resulting binding name `Field`")
})
t.Run("autogen event", func(t *testing.T) {
check(t, "invalid7", true, "error during generation: named type `invalid7.SomeStruct` has two fields with identical resulting binding name `Field`")
})
t.Run("struct", func(t *testing.T) {
check(t, "invalid8", false, "error during generation: named type `invalid8.SomeStruct` has two fields with identical resulting binding name `Field`")
})
})
}

View file

@ -8,6 +8,7 @@ import (
"github.com/nspcc-dev/neo-go/cli/cmdargs" "github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
@ -37,7 +38,7 @@ func manifestAddGroup(ctx *cli.Context) error {
h := state.CreateContractHash(sender, nf.Checksum, m.Name) h := state.CreateContractHash(sender, nf.Checksum, m.Name)
gAcc, w, err := getAccFromContext(ctx) gAcc, w, err := options.GetAccFromContext(ctx)
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1) return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1)
} }
@ -109,7 +110,7 @@ func readManifest(filename string, hash util.Uint160) (*manifest.Manifest, []byt
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if err := m.IsValid(hash); err != nil { if err := m.IsValid(hash, true); err != nil {
return nil, nil, fmt.Errorf("manifest is invalid: %w", err) return nil, nil, fmt.Errorf("manifest is invalid: %w", err)
} }
return m, manifestBytes, nil return m, manifestBytes, nil

View file

@ -1,7 +1,6 @@
package smartcontract package smartcontract
import ( import (
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
@ -28,10 +27,9 @@ func (p permission) MarshalYAML() (any, error) {
&yaml.Node{Kind: yaml.ScalarNode, Value: permHashKey}, &yaml.Node{Kind: yaml.ScalarNode, Value: permHashKey},
&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(util.Uint160).StringLE()}) &yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(util.Uint160).StringLE()})
case manifest.PermissionGroup: case manifest.PermissionGroup:
bs := p.Contract.Value.(*keys.PublicKey).Bytes()
m.Content = append(m.Content, m.Content = append(m.Content,
&yaml.Node{Kind: yaml.ScalarNode, Value: permGroupKey}, &yaml.Node{Kind: yaml.ScalarNode, Value: permGroupKey},
&yaml.Node{Kind: yaml.ScalarNode, Value: hex.EncodeToString(bs)}) &yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(*keys.PublicKey).StringCompressed()})
default: default:
return nil, fmt.Errorf("invalid permission type: %d", p.Contract.Type) return nil, fmt.Errorf("invalid permission type: %d", p.Contract.Type)
} }

View file

@ -11,19 +11,17 @@ import (
"github.com/nspcc-dev/neo-go/cli/cmdargs" "github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/txctx" "github.com/nspcc-dev/neo-go/cli/txctx"
cliwallet "github.com/nspcc-dev/neo-go/cli/wallet"
"github.com/nspcc-dev/neo-go/pkg/compiler" "github.com/nspcc-dev/neo-go/pkg/compiler"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker" "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/management" "github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/binding"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
@ -38,25 +36,14 @@ import (
const addressFlagName = "address, a" const addressFlagName = "address, a"
var ( var (
errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag") errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag")
errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag") errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag")
errNoManifestFile = errors.New("no manifest file was found, specify manifest file with '--manifest' or '-m' flag") errNoManifestFile = errors.New("no manifest file was found, specify manifest file with '--manifest' or '-m' flag")
errNoMethod = errors.New("no method specified for function invocation command") errNoMethod = errors.New("no method specified for function invocation command")
errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag") errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location") errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument") errFileExist = errors.New("A file with given smart-contract name already exists")
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag") addressFlag = flags.AddressFlag{
errFileExist = errors.New("A file with given smart-contract name already exists")
walletFlag = cli.StringFlag{
Name: "wallet, w",
Usage: "wallet to use to get the key for transaction signing; conflicts with --wallet-config flag",
}
walletConfigFlag = cli.StringFlag{
Name: "wallet-config",
Usage: "path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag",
}
addressFlag = flags.AddressFlag{
Name: addressFlagName, Name: addressFlagName,
Usage: "address to use as transaction signee (and gas source)", Usage: "address to use as transaction signee (and gas source)",
} }
@ -99,14 +86,14 @@ func NewCommands() []cli.Command {
testInvokeFunctionFlags := []cli.Flag{options.Historic} testInvokeFunctionFlags := []cli.Flag{options.Historic}
testInvokeFunctionFlags = append(testInvokeFunctionFlags, options.RPC...) testInvokeFunctionFlags = append(testInvokeFunctionFlags, options.RPC...)
invokeFunctionFlags := []cli.Flag{ invokeFunctionFlags := []cli.Flag{
walletFlag,
walletConfigFlag,
addressFlag, addressFlag,
txctx.GasFlag, txctx.GasFlag,
txctx.SysGasFlag, txctx.SysGasFlag,
txctx.OutFlag, txctx.OutFlag,
txctx.ForceFlag, txctx.ForceFlag,
txctx.AwaitFlag,
} }
invokeFunctionFlags = append(invokeFunctionFlags, options.Wallet...)
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...) invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
deployFlags := append(invokeFunctionFlags, []cli.Flag{ deployFlags := append(invokeFunctionFlags, []cli.Flag{
cli.StringFlag{ cli.StringFlag{
@ -118,6 +105,24 @@ func NewCommands() []cli.Command {
Usage: "Manifest input file (*.manifest.json)", Usage: "Manifest input file (*.manifest.json)",
}, },
}...) }...)
manifestAddGroupFlags := append([]cli.Flag{
cli.StringFlag{
Name: "sender, s",
Usage: "deploy transaction sender",
},
flags.AddressFlag{
Name: addressFlagName, // use the same name for handler code unification.
Usage: "account to sign group with",
},
cli.StringFlag{
Name: "nef, n",
Usage: "path to the NEF file",
},
cli.StringFlag{
Name: "manifest, m",
Usage: "path to the manifest",
},
}, options.Wallet...)
return []cli.Command{{ return []cli.Command{{
Name: "contract", Name: "contract",
Usage: "compile - debug - deploy smart contracts", Usage: "compile - debug - deploy smart contracts",
@ -125,12 +130,20 @@ func NewCommands() []cli.Command {
{ {
Name: "compile", Name: "compile",
Usage: "compile a smart contract to a .nef file", Usage: "compile a smart contract to a .nef file",
UsageText: "neo-go contract compile -i path [-o nef] [-v] [-d] [-m manifest] [-c yaml] [--bindings file] [--no-standards] [--no-events] [--no-permissions]", UsageText: "neo-go contract compile -i path [-o nef] [-v] [-d] [-m manifest] [-c yaml] [--bindings file] [--no-standards] [--no-events] [--no-permissions] [--guess-eventtypes]",
Action: contractCompile, Description: `Compiles given smart contract to a .nef file and emits other associated
information (manifest, bindings configuration, debug information files) if
asked to. If none of --out, --manifest, --config, --bindings flags are specified,
then the output filenames for these flags will be guessed using the contract
name or path provided via --in option by trimming/adding corresponding suffixes
to the common part of the path. In the latter case the configuration filepath
will be guessed from the --in option using the same rule.
`,
Action: contractCompile,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "in, i", Name: "in, i",
Usage: "Input file for the smart contract to be compiled", Usage: "Input file for the smart contract to be compiled (*.go file or directory)",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "out, o", Name: "out, o",
@ -164,6 +177,10 @@ func NewCommands() []cli.Command {
Name: "no-permissions", Name: "no-permissions",
Usage: "do not check if invoked contracts are allowed in manifest", Usage: "do not check if invoked contracts are allowed in manifest",
}, },
cli.BoolFlag{
Name: "guess-eventtypes",
Usage: "guess event types for smart-contract bindings configuration from the code usages",
},
cli.StringFlag{ cli.StringFlag{
Name: "bindings", Name: "bindings",
Usage: "output file for smart-contract bindings configuration", Usage: "output file for smart-contract bindings configuration",
@ -173,10 +190,12 @@ func NewCommands() []cli.Command {
{ {
Name: "deploy", Name: "deploy",
Usage: "deploy a smart contract (.nef with description)", Usage: "deploy a smart contract (.nef with description)",
UsageText: "neo-go contract deploy -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] --in contract.nef --manifest contract.manifest.json [--out file] [--force] [data]", UsageText: "neo-go contract deploy -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] --in contract.nef --manifest contract.manifest.json [--out file] [--force] [--await] [data]",
Description: `Deploys given contract into the chain. The gas parameter is for additional Description: `Deploys given contract into the chain. The gas parameter is for additional
gas to be added as a network fee to prioritize the transaction. The data gas to be added as a network fee to prioritize the transaction. The data
parameter is an optional parameter to be passed to '_deploy' method. parameter is an optional parameter to be passed to '_deploy' method. When
--await flag is specified, it waits for the transaction to be included
in a block.
`, `,
Action: contractDeploy, Action: contractDeploy,
Flags: deployFlags, Flags: deployFlags,
@ -186,13 +205,14 @@ func NewCommands() []cli.Command {
{ {
Name: "invokefunction", Name: "invokefunction",
Usage: "invoke deployed contract on the blockchain", Usage: "invoke deployed contract on the blockchain",
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] [--out file] [--force] scripthash [method] [arguments...] [--] [signers...]", UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] [--out file] [--force] [--await] scripthash [method] [arguments...] [--] [signers...]",
Description: `Executes given (as a script hash) deployed script with the given method, Description: `Executes given (as a script hash) deployed script with the given method,
arguments and signers. Sender is included in the list of signers by default arguments and signers. Sender is included in the list of signers by default
with None witness scope. If you'd like to change default sender's scope, with None witness scope. If you'd like to change default sender's scope,
specify it via signers parameter. See testinvokefunction documentation for specify it via signers parameter. See testinvokefunction documentation for
the details about parameters. It differs from testinvokefunction in that this the details about parameters. It differs from testinvokefunction in that this
command sends an invocation transaction to the network. command sends an invocation transaction to the network. When --await flag is
specified, it waits for the transaction to be included in a block.
`, `,
Action: invokeFunction, Action: invokeFunction,
Flags: invokeFunctionFlags, Flags: invokeFunctionFlags,
@ -289,26 +309,7 @@ func NewCommands() []cli.Command {
Usage: "adds group to the manifest", Usage: "adds group to the manifest",
UsageText: "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address", UsageText: "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address",
Action: manifestAddGroup, Action: manifestAddGroup,
Flags: []cli.Flag{ Flags: manifestAddGroupFlags,
walletFlag,
walletConfigFlag,
cli.StringFlag{
Name: "sender, s",
Usage: "deploy transaction sender",
},
flags.AddressFlag{
Name: addressFlagName, // use the same name for handler code unification.
Usage: "account to sign group with",
},
cli.StringFlag{
Name: "nef, n",
Usage: "path to the NEF file",
},
cli.StringFlag{
Name: "manifest, m",
Usage: "path to the manifest",
},
},
}, },
}, },
}, },
@ -345,13 +346,15 @@ func initSmartContract(ctx *cli.Context) error {
SourceURL: "http://example.com/", SourceURL: "http://example.com/",
SupportedStandards: []string{}, SupportedStandards: []string{},
SafeMethods: []string{}, SafeMethods: []string{},
Events: []manifest.Event{ Events: []compiler.HybridEvent{
{ {
Name: "Hello world!", Name: "Hello world!",
Parameters: []manifest.Parameter{ Parameters: []compiler.HybridParameter{
{ {
Name: "args", Parameter: manifest.Parameter{
Type: smartcontract.ArrayType, Name: "args",
Type: smartcontract.ArrayType,
},
}, },
}, },
}, },
@ -372,6 +375,9 @@ func initSmartContract(ctx *cli.Context) error {
} }
gm := []byte("module " + contractName + ` gm := []byte("module " + contractName + `
go 1.20
require ( require (
github.com/nspcc-dev/neo-go/pkg/interop ` + ver + ` github.com/nspcc-dev/neo-go/pkg/interop ` + ver + `
)`) )`)
@ -400,20 +406,48 @@ func contractCompile(ctx *cli.Context) error {
manifestFile := ctx.String("manifest") manifestFile := ctx.String("manifest")
confFile := ctx.String("config") confFile := ctx.String("config")
debugFile := ctx.String("debug") debugFile := ctx.String("debug")
if len(confFile) == 0 && (len(manifestFile) != 0 || len(debugFile) != 0) { out := ctx.String("out")
bindings := ctx.String("bindings")
if len(confFile) == 0 && (len(manifestFile) != 0 || len(debugFile) != 0 || len(bindings) != 0) {
return cli.NewExitError(errNoConfFile, 1) return cli.NewExitError(errNoConfFile, 1)
} }
autocomplete := len(manifestFile) == 0 &&
len(confFile) == 0 &&
len(out) == 0 &&
len(bindings) == 0
if autocomplete {
var root string
fileInfo, err := os.Stat(src)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to stat source file or directory: %w", err), 1)
}
if fileInfo.IsDir() {
base := filepath.Base(fileInfo.Name())
if base == string(filepath.Separator) {
base = "contract"
}
root = filepath.Join(src, base)
} else {
root = strings.TrimSuffix(src, ".go")
}
manifestFile = root + ".manifest.json"
confFile = root + ".yml"
out = root + ".nef"
bindings = root + ".bindings.yml"
}
o := &compiler.Options{ o := &compiler.Options{
Outfile: ctx.String("out"), Outfile: out,
DebugInfo: debugFile, DebugInfo: debugFile,
ManifestFile: manifestFile, ManifestFile: manifestFile,
BindingsFile: ctx.String("bindings"), BindingsFile: bindings,
NoStandardCheck: ctx.Bool("no-standards"), NoStandardCheck: ctx.Bool("no-standards"),
NoEventsCheck: ctx.Bool("no-events"), NoEventsCheck: ctx.Bool("no-events"),
NoPermissionsCheck: ctx.Bool("no-permissions"), NoPermissionsCheck: ctx.Bool("no-permissions"),
GuessEventTypes: ctx.Bool("guess-eventtypes"),
} }
if len(confFile) != 0 { if len(confFile) != 0 {
@ -424,6 +458,7 @@ func contractCompile(ctx *cli.Context) error {
o.Name = conf.Name o.Name = conf.Name
o.SourceURL = conf.SourceURL o.SourceURL = conf.SourceURL
o.ContractEvents = conf.Events o.ContractEvents = conf.Events
o.DeclaredNamedTypes = conf.NamedTypes
o.ContractSupportedStandards = conf.SupportedStandards o.ContractSupportedStandards = conf.SupportedStandards
o.Permissions = make([]manifest.Permission, len(conf.Permissions)) o.Permissions = make([]manifest.Permission, len(conf.Permissions))
for i := range conf.Permissions { for i := range conf.Permissions {
@ -538,7 +573,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
w *wallet.Wallet w *wallet.Wallet
) )
if signAndPush { if signAndPush {
acc, w, err = getAccFromContext(ctx) acc, w, err = options.GetAccFromContext(ctx)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -565,19 +600,14 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
} }
gctx, cancel := options.GetTimeoutContext(ctx) gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel() defer cancel()
c, err := options.GetRPCClient(gctx, ctx)
if err != nil {
return err
}
if signAndPush { if signAndPush {
act, err = actor.New(c, signersAccounts) _, act, err = options.GetRPCWithActor(gctx, ctx, signersAccounts)
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1) return err
} }
inv = &act.Invoker inv = &act.Invoker
} else { } else {
inv, err = options.GetInvoker(c, ctx, cosigners) _, inv, err = options.GetRPCWithInvoker(gctx, ctx, cosigners)
if err != nil { if err != nil {
return err return err
} }
@ -672,9 +702,10 @@ type ProjectConfig struct {
SourceURL string SourceURL string
SafeMethods []string SafeMethods []string
SupportedStandards []string SupportedStandards []string
Events []manifest.Event Events []compiler.HybridEvent
Permissions []permission Permissions []permission
Overloads map[string]string `yaml:"overloads,omitempty"` Overloads map[string]string `yaml:"overloads,omitempty"`
NamedTypes map[string]binding.ExtendedType `yaml:"namedtypes,omitempty"`
} }
func inspect(ctx *cli.Context) error { func inspect(ctx *cli.Context) error {
@ -713,68 +744,6 @@ func inspect(ctx *cli.Context) error {
return nil return nil
} }
func getAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error) {
var addr util.Uint160
wPath := ctx.String("wallet")
walletConfigPath := ctx.String("wallet-config")
if len(wPath) != 0 && len(walletConfigPath) != 0 {
return nil, nil, errConflictingWalletFlags
}
if len(wPath) == 0 && len(walletConfigPath) == 0 {
return nil, nil, errNoWallet
}
var pass *string
if len(walletConfigPath) != 0 {
cfg, err := cliwallet.ReadWalletConfig(walletConfigPath)
if err != nil {
return nil, nil, err
}
wPath = cfg.Path
pass = &cfg.Password
}
wall, err := wallet.NewWalletFromFile(wPath)
if err != nil {
return nil, nil, err
}
addrFlag := ctx.Generic("address").(*flags.Address)
if addrFlag.IsSet {
addr = addrFlag.Uint160()
} else {
addr = wall.GetChangeAddress()
}
acc, err := getUnlockedAccount(wall, addr, pass)
return acc, wall, err
}
func getUnlockedAccount(wall *wallet.Wallet, addr util.Uint160, pass *string) (*wallet.Account, error) {
acc := wall.GetAccount(addr)
if acc == nil {
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
}
if acc.CanSign() {
return acc, nil
}
if pass == nil {
rawPass, err := input.ReadPassword(
fmt.Sprintf("Enter account %s password > ", address.Uint160ToString(addr)))
if err != nil {
return nil, fmt.Errorf("Error reading password: %w", err)
}
trimmed := strings.TrimRight(string(rawPass), "\n")
pass = &trimmed
}
err := acc.Decrypt(*pass, wall.Scrypt)
if err != nil {
return nil, err
}
return acc, nil
}
// contractDeploy deploys contract. // contractDeploy deploys contract.
func contractDeploy(ctx *cli.Context) error { func contractDeploy(ctx *cli.Context) error {
nefFile, f, err := readNEFFile(ctx.String("in")) nefFile, f, err := readNEFFile(ctx.String("in"))
@ -800,7 +769,7 @@ func contractDeploy(ctx *cli.Context) error {
appCallParams = append(appCallParams, data[0]) appCallParams = append(appCallParams, data[0])
} }
acc, w, err := getAccFromContext(ctx) acc, w, err := options.GetAccFromContext(ctx)
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1) return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
} }

View file

@ -1,7 +1,6 @@
package smartcontract package smartcontract
import ( import (
"encoding/hex"
"flag" "flag"
"os" "os"
"testing" "testing"
@ -109,7 +108,7 @@ func TestPermissionMarshal(t *testing.T) {
p.Methods.Add("abc") p.Methods.Add("abc")
p.Methods.Add("lamao") p.Methods.Add("lamao")
testPermissionMarshal(t, p, testPermissionMarshal(t, p,
"group: "+hex.EncodeToString(priv.PublicKey().Bytes())+"\n"+ "group: "+priv.PublicKey().StringCompressed()+"\n"+
"methods:\n - abc\n - lamao\n") "methods:\n - abc\n - lamao\n")
}) })
} }
@ -118,7 +117,7 @@ func TestPermissionUnmarshalInvalid(t *testing.T) {
priv, err := keys.NewPrivateKey() priv, err := keys.NewPrivateKey()
require.NoError(t, err) require.NoError(t, err)
pub := hex.EncodeToString(priv.PublicKey().Bytes()) pub := priv.PublicKey().StringCompressed()
u160 := random.Uint160().StringLE() u160 := random.Uint160().StringLE()
testCases := []string{ testCases := []string{
"hash: []\nmethods: '*'\n", // invalid hash type "hash: []\nmethods: '*'\n", // invalid hash type

View file

@ -1,3 +1,5 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package gastoken contains RPC wrappers for GasToken contract. // Package gastoken contains RPC wrappers for GasToken contract.
package gastoken package gastoken
@ -25,6 +27,7 @@ type Actor interface {
type ContractReader struct { type ContractReader struct {
nep17.TokenReader nep17.TokenReader
invoker Invoker invoker Invoker
hash util.Uint160
} }
// Contract implements all contract methods. // Contract implements all contract methods.
@ -32,16 +35,18 @@ type Contract struct {
ContractReader ContractReader
nep17.TokenWriter nep17.TokenWriter
actor Actor actor Actor
hash util.Uint160
} }
// NewReader creates an instance of ContractReader using Hash and the given Invoker. // NewReader creates an instance of ContractReader using Hash and the given Invoker.
func NewReader(invoker Invoker) *ContractReader { func NewReader(invoker Invoker) *ContractReader {
return &ContractReader{*nep17.NewReader(invoker, Hash), invoker} var hash = Hash
return &ContractReader{*nep17.NewReader(invoker, hash), invoker, hash}
} }
// New creates an instance of Contract using Hash and the given Actor. // New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract { func New(actor Actor) *Contract {
var nep17t = nep17.New(actor, Hash) var hash = Hash
return &Contract{ContractReader{nep17t.TokenReader, actor}, nep17t.TokenWriter, actor} var nep17t = nep17.New(actor, hash)
return &Contract{ContractReader{nep17t.TokenReader, actor, hash}, nep17t.TokenWriter, actor, hash}
} }

View file

@ -1,7 +1,11 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package nameservice contains RPC wrappers for NameService contract. // Package nameservice contains RPC wrappers for NameService contract.
package nameservice package nameservice
import ( import (
"errors"
"fmt"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/neorpc/result"
@ -11,11 +15,26 @@ import (
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"math/big" "math/big"
"unicode/utf8"
) )
// Hash contains contract hash. // Hash contains contract hash.
var Hash = util.Uint160{0xde, 0x46, 0x5f, 0x5d, 0x50, 0x57, 0xcf, 0x33, 0x28, 0x47, 0x94, 0xc5, 0xcf, 0xc2, 0xc, 0x69, 0x37, 0x1c, 0xac, 0x50} var Hash = util.Uint160{0xde, 0x46, 0x5f, 0x5d, 0x50, 0x57, 0xcf, 0x33, 0x28, 0x47, 0x94, 0xc5, 0xcf, 0xc2, 0xc, 0x69, 0x37, 0x1c, 0xac, 0x50}
// SetAdminEvent represents "SetAdmin" event emitted by the contract.
type SetAdminEvent struct {
Name string
OldAdmin util.Uint160
NewAdmin util.Uint160
}
// RenewEvent represents "Renew" event emitted by the contract.
type RenewEvent struct {
Name string
OldExpiration *big.Int
NewExpiration *big.Int
}
// Invoker is used by ContractReader to call various safe methods. // Invoker is used by ContractReader to call various safe methods.
type Invoker interface { type Invoker interface {
nep11.Invoker nep11.Invoker
@ -39,6 +58,7 @@ type Actor interface {
type ContractReader struct { type ContractReader struct {
nep11.NonDivisibleReader nep11.NonDivisibleReader
invoker Invoker invoker Invoker
hash util.Uint160
} }
// Contract implements all contract methods. // Contract implements all contract methods.
@ -46,23 +66,25 @@ type Contract struct {
ContractReader ContractReader
nep11.BaseWriter nep11.BaseWriter
actor Actor actor Actor
hash util.Uint160
} }
// NewReader creates an instance of ContractReader using Hash and the given Invoker. // NewReader creates an instance of ContractReader using Hash and the given Invoker.
func NewReader(invoker Invoker) *ContractReader { func NewReader(invoker Invoker) *ContractReader {
return &ContractReader{*nep11.NewNonDivisibleReader(invoker, Hash), invoker} var hash = Hash
return &ContractReader{*nep11.NewNonDivisibleReader(invoker, hash), invoker, hash}
} }
// New creates an instance of Contract using Hash and the given Actor. // New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract { func New(actor Actor) *Contract {
var nep11ndt = nep11.NewNonDivisible(actor, Hash) var hash = Hash
return &Contract{ContractReader{nep11ndt.NonDivisibleReader, actor}, nep11ndt.BaseWriter, actor} var nep11ndt = nep11.NewNonDivisible(actor, hash)
return &Contract{ContractReader{nep11ndt.NonDivisibleReader, actor, hash}, nep11ndt.BaseWriter, actor, hash}
} }
// Roots invokes `roots` method of contract. // Roots invokes `roots` method of contract.
func (c *ContractReader) Roots() (uuid.UUID, result.Iterator, error) { func (c *ContractReader) Roots() (uuid.UUID, result.Iterator, error) {
return unwrap.SessionIterator(c.invoker.Call(Hash, "roots")) return unwrap.SessionIterator(c.invoker.Call(c.hash, "roots"))
} }
// RootsExpanded is similar to Roots (uses the same contract // RootsExpanded is similar to Roots (uses the same contract
@ -71,27 +93,27 @@ func (c *ContractReader) Roots() (uuid.UUID, result.Iterator, error) {
// number of result items from the iterator right in the VM and return them to // number of result items from the iterator right in the VM and return them to
// you. It's only limited by VM stack and GAS available for RPC invocations. // you. It's only limited by VM stack and GAS available for RPC invocations.
func (c *ContractReader) RootsExpanded(_numOfIteratorItems int) ([]stackitem.Item, error) { func (c *ContractReader) RootsExpanded(_numOfIteratorItems int) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.CallAndExpandIterator(Hash, "roots", _numOfIteratorItems)) return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "roots", _numOfIteratorItems))
} }
// GetPrice invokes `getPrice` method of contract. // GetPrice invokes `getPrice` method of contract.
func (c *ContractReader) GetPrice(length *big.Int) (*big.Int, error) { func (c *ContractReader) GetPrice(length *big.Int) (*big.Int, error) {
return unwrap.BigInt(c.invoker.Call(Hash, "getPrice", length)) return unwrap.BigInt(c.invoker.Call(c.hash, "getPrice", length))
} }
// IsAvailable invokes `isAvailable` method of contract. // IsAvailable invokes `isAvailable` method of contract.
func (c *ContractReader) IsAvailable(name string) (bool, error) { func (c *ContractReader) IsAvailable(name string) (bool, error) {
return unwrap.Bool(c.invoker.Call(Hash, "isAvailable", name)) return unwrap.Bool(c.invoker.Call(c.hash, "isAvailable", name))
} }
// GetRecord invokes `getRecord` method of contract. // GetRecord invokes `getRecord` method of contract.
func (c *ContractReader) GetRecord(name string, typev *big.Int) (string, error) { func (c *ContractReader) GetRecord(name string, typev *big.Int) (string, error) {
return unwrap.UTF8String(c.invoker.Call(Hash, "getRecord", name, typev)) return unwrap.UTF8String(c.invoker.Call(c.hash, "getRecord", name, typev))
} }
// GetAllRecords invokes `getAllRecords` method of contract. // GetAllRecords invokes `getAllRecords` method of contract.
func (c *ContractReader) GetAllRecords(name string) (uuid.UUID, result.Iterator, error) { func (c *ContractReader) GetAllRecords(name string) (uuid.UUID, result.Iterator, error) {
return unwrap.SessionIterator(c.invoker.Call(Hash, "getAllRecords", name)) return unwrap.SessionIterator(c.invoker.Call(c.hash, "getAllRecords", name))
} }
// GetAllRecordsExpanded is similar to GetAllRecords (uses the same contract // GetAllRecordsExpanded is similar to GetAllRecords (uses the same contract
@ -100,26 +122,26 @@ func (c *ContractReader) GetAllRecords(name string) (uuid.UUID, result.Iterator,
// number of result items from the iterator right in the VM and return them to // number of result items from the iterator right in the VM and return them to
// you. It's only limited by VM stack and GAS available for RPC invocations. // you. It's only limited by VM stack and GAS available for RPC invocations.
func (c *ContractReader) GetAllRecordsExpanded(name string, _numOfIteratorItems int) ([]stackitem.Item, error) { func (c *ContractReader) GetAllRecordsExpanded(name string, _numOfIteratorItems int) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.CallAndExpandIterator(Hash, "getAllRecords", _numOfIteratorItems, name)) return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "getAllRecords", _numOfIteratorItems, name))
} }
// Resolve invokes `resolve` method of contract. // Resolve invokes `resolve` method of contract.
func (c *ContractReader) Resolve(name string, typev *big.Int) (string, error) { func (c *ContractReader) Resolve(name string, typev *big.Int) (string, error) {
return unwrap.UTF8String(c.invoker.Call(Hash, "resolve", name, typev)) return unwrap.UTF8String(c.invoker.Call(c.hash, "resolve", name, typev))
} }
// Update creates a transaction invoking `update` method of the contract. // Update creates a transaction invoking `update` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Update(nef []byte, manifest string) (util.Uint256, uint32, error) { func (c *Contract) Update(nef []byte, manifest string) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "update", nef, manifest) return c.actor.SendCall(c.hash, "update", nef, manifest)
} }
// UpdateTransaction creates a transaction invoking `update` method of the contract. // UpdateTransaction creates a transaction invoking `update` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) UpdateTransaction(nef []byte, manifest string) (*transaction.Transaction, error) { func (c *Contract) UpdateTransaction(nef []byte, manifest string) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "update", nef, manifest) return c.actor.MakeCall(c.hash, "update", nef, manifest)
} }
// UpdateUnsigned creates a transaction invoking `update` method of the contract. // UpdateUnsigned creates a transaction invoking `update` method of the contract.
@ -127,21 +149,21 @@ func (c *Contract) UpdateTransaction(nef []byte, manifest string) (*transaction.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) UpdateUnsigned(nef []byte, manifest string) (*transaction.Transaction, error) { func (c *Contract) UpdateUnsigned(nef []byte, manifest string) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "update", nil, nef, manifest) return c.actor.MakeUnsignedCall(c.hash, "update", nil, nef, manifest)
} }
// AddRoot creates a transaction invoking `addRoot` method of the contract. // AddRoot creates a transaction invoking `addRoot` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) AddRoot(root string) (util.Uint256, uint32, error) { func (c *Contract) AddRoot(root string) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "addRoot", root) return c.actor.SendCall(c.hash, "addRoot", root)
} }
// AddRootTransaction creates a transaction invoking `addRoot` method of the contract. // AddRootTransaction creates a transaction invoking `addRoot` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) AddRootTransaction(root string) (*transaction.Transaction, error) { func (c *Contract) AddRootTransaction(root string) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "addRoot", root) return c.actor.MakeCall(c.hash, "addRoot", root)
} }
// AddRootUnsigned creates a transaction invoking `addRoot` method of the contract. // AddRootUnsigned creates a transaction invoking `addRoot` method of the contract.
@ -149,21 +171,21 @@ func (c *Contract) AddRootTransaction(root string) (*transaction.Transaction, er
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) AddRootUnsigned(root string) (*transaction.Transaction, error) { func (c *Contract) AddRootUnsigned(root string) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "addRoot", nil, root) return c.actor.MakeUnsignedCall(c.hash, "addRoot", nil, root)
} }
// SetPrice creates a transaction invoking `setPrice` method of the contract. // SetPrice creates a transaction invoking `setPrice` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) SetPrice(priceList []any) (util.Uint256, uint32, error) { func (c *Contract) SetPrice(priceList []any) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "setPrice", priceList) return c.actor.SendCall(c.hash, "setPrice", priceList)
} }
// SetPriceTransaction creates a transaction invoking `setPrice` method of the contract. // SetPriceTransaction creates a transaction invoking `setPrice` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) SetPriceTransaction(priceList []any) (*transaction.Transaction, error) { func (c *Contract) SetPriceTransaction(priceList []any) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "setPrice", priceList) return c.actor.MakeCall(c.hash, "setPrice", priceList)
} }
// SetPriceUnsigned creates a transaction invoking `setPrice` method of the contract. // SetPriceUnsigned creates a transaction invoking `setPrice` method of the contract.
@ -171,18 +193,18 @@ func (c *Contract) SetPriceTransaction(priceList []any) (*transaction.Transactio
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) SetPriceUnsigned(priceList []any) (*transaction.Transaction, error) { func (c *Contract) SetPriceUnsigned(priceList []any) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "setPrice", nil, priceList) return c.actor.MakeUnsignedCall(c.hash, "setPrice", nil, priceList)
} }
func scriptForRegister(name string, owner util.Uint160) ([]byte, error) { func (c *Contract) scriptForRegister(name string, owner util.Uint160) ([]byte, error) {
return smartcontract.CreateCallWithAssertScript(Hash, "register", name, owner) return smartcontract.CreateCallWithAssertScript(c.hash, "register", name, owner)
} }
// Register creates a transaction invoking `register` method of the contract. // Register creates a transaction invoking `register` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Register(name string, owner util.Uint160) (util.Uint256, uint32, error) { func (c *Contract) Register(name string, owner util.Uint160) (util.Uint256, uint32, error) {
script, err := scriptForRegister(name, owner) script, err := c.scriptForRegister(name, owner)
if err != nil { if err != nil {
return util.Uint256{}, 0, err return util.Uint256{}, 0, err
} }
@ -193,7 +215,7 @@ func (c *Contract) Register(name string, owner util.Uint160) (util.Uint256, uint
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) RegisterTransaction(name string, owner util.Uint160) (*transaction.Transaction, error) { func (c *Contract) RegisterTransaction(name string, owner util.Uint160) (*transaction.Transaction, error) {
script, err := scriptForRegister(name, owner) script, err := c.scriptForRegister(name, owner)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -205,7 +227,7 @@ func (c *Contract) RegisterTransaction(name string, owner util.Uint160) (*transa
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) RegisterUnsigned(name string, owner util.Uint160) (*transaction.Transaction, error) { func (c *Contract) RegisterUnsigned(name string, owner util.Uint160) (*transaction.Transaction, error) {
script, err := scriptForRegister(name, owner) script, err := c.scriptForRegister(name, owner)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -216,14 +238,14 @@ func (c *Contract) RegisterUnsigned(name string, owner util.Uint160) (*transacti
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Renew(name string) (util.Uint256, uint32, error) { func (c *Contract) Renew(name string) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "renew", name) return c.actor.SendCall(c.hash, "renew", name)
} }
// RenewTransaction creates a transaction invoking `renew` method of the contract. // RenewTransaction creates a transaction invoking `renew` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) RenewTransaction(name string) (*transaction.Transaction, error) { func (c *Contract) RenewTransaction(name string) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "renew", name) return c.actor.MakeCall(c.hash, "renew", name)
} }
// RenewUnsigned creates a transaction invoking `renew` method of the contract. // RenewUnsigned creates a transaction invoking `renew` method of the contract.
@ -231,43 +253,43 @@ func (c *Contract) RenewTransaction(name string) (*transaction.Transaction, erro
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) RenewUnsigned(name string) (*transaction.Transaction, error) { func (c *Contract) RenewUnsigned(name string) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "renew", nil, name) return c.actor.MakeUnsignedCall(c.hash, "renew", nil, name)
} }
// Renew_2 creates a transaction invoking `renew` method of the contract. // Renew2 creates a transaction invoking `renew` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Renew_2(name string, years *big.Int) (util.Uint256, uint32, error) { func (c *Contract) Renew2(name string, years *big.Int) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "renew", name, years) return c.actor.SendCall(c.hash, "renew", name, years)
} }
// Renew_2Transaction creates a transaction invoking `renew` method of the contract. // Renew2Transaction creates a transaction invoking `renew` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) Renew_2Transaction(name string, years *big.Int) (*transaction.Transaction, error) { func (c *Contract) Renew2Transaction(name string, years *big.Int) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "renew", name, years) return c.actor.MakeCall(c.hash, "renew", name, years)
} }
// Renew_2Unsigned creates a transaction invoking `renew` method of the contract. // Renew2Unsigned creates a transaction invoking `renew` method of the contract.
// This transaction is not signed, it's simply returned to the caller. // This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) Renew_2Unsigned(name string, years *big.Int) (*transaction.Transaction, error) { func (c *Contract) Renew2Unsigned(name string, years *big.Int) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "renew", nil, name, years) return c.actor.MakeUnsignedCall(c.hash, "renew", nil, name, years)
} }
// SetAdmin creates a transaction invoking `setAdmin` method of the contract. // SetAdmin creates a transaction invoking `setAdmin` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) SetAdmin(name string, admin util.Uint160) (util.Uint256, uint32, error) { func (c *Contract) SetAdmin(name string, admin util.Uint160) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "setAdmin", name, admin) return c.actor.SendCall(c.hash, "setAdmin", name, admin)
} }
// SetAdminTransaction creates a transaction invoking `setAdmin` method of the contract. // SetAdminTransaction creates a transaction invoking `setAdmin` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) SetAdminTransaction(name string, admin util.Uint160) (*transaction.Transaction, error) { func (c *Contract) SetAdminTransaction(name string, admin util.Uint160) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "setAdmin", name, admin) return c.actor.MakeCall(c.hash, "setAdmin", name, admin)
} }
// SetAdminUnsigned creates a transaction invoking `setAdmin` method of the contract. // SetAdminUnsigned creates a transaction invoking `setAdmin` method of the contract.
@ -275,21 +297,21 @@ func (c *Contract) SetAdminTransaction(name string, admin util.Uint160) (*transa
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) SetAdminUnsigned(name string, admin util.Uint160) (*transaction.Transaction, error) { func (c *Contract) SetAdminUnsigned(name string, admin util.Uint160) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "setAdmin", nil, name, admin) return c.actor.MakeUnsignedCall(c.hash, "setAdmin", nil, name, admin)
} }
// SetRecord creates a transaction invoking `setRecord` method of the contract. // SetRecord creates a transaction invoking `setRecord` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) SetRecord(name string, typev *big.Int, data string) (util.Uint256, uint32, error) { func (c *Contract) SetRecord(name string, typev *big.Int, data string) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "setRecord", name, typev, data) return c.actor.SendCall(c.hash, "setRecord", name, typev, data)
} }
// SetRecordTransaction creates a transaction invoking `setRecord` method of the contract. // SetRecordTransaction creates a transaction invoking `setRecord` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) SetRecordTransaction(name string, typev *big.Int, data string) (*transaction.Transaction, error) { func (c *Contract) SetRecordTransaction(name string, typev *big.Int, data string) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "setRecord", name, typev, data) return c.actor.MakeCall(c.hash, "setRecord", name, typev, data)
} }
// SetRecordUnsigned creates a transaction invoking `setRecord` method of the contract. // SetRecordUnsigned creates a transaction invoking `setRecord` method of the contract.
@ -297,21 +319,21 @@ func (c *Contract) SetRecordTransaction(name string, typev *big.Int, data string
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) SetRecordUnsigned(name string, typev *big.Int, data string) (*transaction.Transaction, error) { func (c *Contract) SetRecordUnsigned(name string, typev *big.Int, data string) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "setRecord", nil, name, typev, data) return c.actor.MakeUnsignedCall(c.hash, "setRecord", nil, name, typev, data)
} }
// DeleteRecord creates a transaction invoking `deleteRecord` method of the contract. // DeleteRecord creates a transaction invoking `deleteRecord` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) DeleteRecord(name string, typev *big.Int) (util.Uint256, uint32, error) { func (c *Contract) DeleteRecord(name string, typev *big.Int) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "deleteRecord", name, typev) return c.actor.SendCall(c.hash, "deleteRecord", name, typev)
} }
// DeleteRecordTransaction creates a transaction invoking `deleteRecord` method of the contract. // DeleteRecordTransaction creates a transaction invoking `deleteRecord` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) DeleteRecordTransaction(name string, typev *big.Int) (*transaction.Transaction, error) { func (c *Contract) DeleteRecordTransaction(name string, typev *big.Int) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "deleteRecord", name, typev) return c.actor.MakeCall(c.hash, "deleteRecord", name, typev)
} }
// DeleteRecordUnsigned creates a transaction invoking `deleteRecord` method of the contract. // DeleteRecordUnsigned creates a transaction invoking `deleteRecord` method of the contract.
@ -319,5 +341,171 @@ func (c *Contract) DeleteRecordTransaction(name string, typev *big.Int) (*transa
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) DeleteRecordUnsigned(name string, typev *big.Int) (*transaction.Transaction, error) { func (c *Contract) DeleteRecordUnsigned(name string, typev *big.Int) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "deleteRecord", nil, name, typev) return c.actor.MakeUnsignedCall(c.hash, "deleteRecord", nil, name, typev)
}
// SetAdminEventsFromApplicationLog retrieves a set of all emitted events
// with "SetAdmin" name from the provided [result.ApplicationLog].
func SetAdminEventsFromApplicationLog(log *result.ApplicationLog) ([]*SetAdminEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SetAdminEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SetAdmin" {
continue
}
event := new(SetAdminEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SetAdminEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SetAdminEvent or
// returns an error if it's not possible to do to so.
func (e *SetAdminEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 3 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.Name, err = func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[index])
if err != nil {
return fmt.Errorf("field Name: %w", err)
}
index++
e.OldAdmin, err = func(item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field OldAdmin: %w", err)
}
index++
e.NewAdmin, err = func(item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field NewAdmin: %w", err)
}
return nil
}
// RenewEventsFromApplicationLog retrieves a set of all emitted events
// with "Renew" name from the provided [result.ApplicationLog].
func RenewEventsFromApplicationLog(log *result.ApplicationLog) ([]*RenewEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*RenewEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "Renew" {
continue
}
event := new(RenewEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize RenewEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to RenewEvent or
// returns an error if it's not possible to do to so.
func (e *RenewEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 3 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.Name, err = func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[index])
if err != nil {
return fmt.Errorf("field Name: %w", err)
}
index++
e.OldExpiration, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field OldExpiration: %w", err)
}
index++
e.NewExpiration, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field NewExpiration: %w", err)
}
return nil
} }

View file

@ -1,18 +1,32 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package nextoken contains RPC wrappers for NEX Token contract. // Package nextoken contains RPC wrappers for NEX Token contract.
package nextoken package nextoken
import ( import (
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17" "github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap" "github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"math/big" "math/big"
) )
// Hash contains contract hash. // Hash contains contract hash.
var Hash = util.Uint160{0xa8, 0x1a, 0xa1, 0xf0, 0x4b, 0xf, 0xdc, 0x4a, 0xa2, 0xce, 0xd5, 0xbf, 0xc6, 0x22, 0xcf, 0xe8, 0x9, 0x7f, 0xa6, 0xa2} var Hash = util.Uint160{0xa8, 0x1a, 0xa1, 0xf0, 0x4b, 0xf, 0xdc, 0x4a, 0xa2, 0xce, 0xd5, 0xbf, 0xc6, 0x22, 0xcf, 0xe8, 0x9, 0x7f, 0xa6, 0xa2}
// OnMintEvent represents "OnMint" event emitted by the contract.
type OnMintEvent struct {
From util.Uint160
To util.Uint160
Amount *big.Int
SwapId *big.Int
}
// Invoker is used by ContractReader to call various safe methods. // Invoker is used by ContractReader to call various safe methods.
type Invoker interface { type Invoker interface {
nep17.Invoker nep17.Invoker
@ -36,6 +50,7 @@ type Actor interface {
type ContractReader struct { type ContractReader struct {
nep17.TokenReader nep17.TokenReader
invoker Invoker invoker Invoker
hash util.Uint160
} }
// Contract implements all contract methods. // Contract implements all contract methods.
@ -43,52 +58,54 @@ type Contract struct {
ContractReader ContractReader
nep17.TokenWriter nep17.TokenWriter
actor Actor actor Actor
hash util.Uint160
} }
// NewReader creates an instance of ContractReader using Hash and the given Invoker. // NewReader creates an instance of ContractReader using Hash and the given Invoker.
func NewReader(invoker Invoker) *ContractReader { func NewReader(invoker Invoker) *ContractReader {
return &ContractReader{*nep17.NewReader(invoker, Hash), invoker} var hash = Hash
return &ContractReader{*nep17.NewReader(invoker, hash), invoker, hash}
} }
// New creates an instance of Contract using Hash and the given Actor. // New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract { func New(actor Actor) *Contract {
var nep17t = nep17.New(actor, Hash) var hash = Hash
return &Contract{ContractReader{nep17t.TokenReader, actor}, nep17t.TokenWriter, actor} var nep17t = nep17.New(actor, hash)
return &Contract{ContractReader{nep17t.TokenReader, actor, hash}, nep17t.TokenWriter, actor, hash}
} }
// Cap invokes `cap` method of contract. // Cap invokes `cap` method of contract.
func (c *ContractReader) Cap() (*big.Int, error) { func (c *ContractReader) Cap() (*big.Int, error) {
return unwrap.BigInt(c.invoker.Call(Hash, "cap")) return unwrap.BigInt(c.invoker.Call(c.hash, "cap"))
} }
// GetMinter invokes `getMinter` method of contract. // GetMinter invokes `getMinter` method of contract.
func (c *ContractReader) GetMinter() (*keys.PublicKey, error) { func (c *ContractReader) GetMinter() (*keys.PublicKey, error) {
return unwrap.PublicKey(c.invoker.Call(Hash, "getMinter")) return unwrap.PublicKey(c.invoker.Call(c.hash, "getMinter"))
} }
// GetOwner invokes `getOwner` method of contract. // GetOwner invokes `getOwner` method of contract.
func (c *ContractReader) GetOwner() (util.Uint160, error) { func (c *ContractReader) GetOwner() (util.Uint160, error) {
return unwrap.Uint160(c.invoker.Call(Hash, "getOwner")) return unwrap.Uint160(c.invoker.Call(c.hash, "getOwner"))
} }
// TotalMinted invokes `totalMinted` method of contract. // TotalMinted invokes `totalMinted` method of contract.
func (c *ContractReader) TotalMinted() (*big.Int, error) { func (c *ContractReader) TotalMinted() (*big.Int, error) {
return unwrap.BigInt(c.invoker.Call(Hash, "totalMinted")) return unwrap.BigInt(c.invoker.Call(c.hash, "totalMinted"))
} }
// ChangeMinter creates a transaction invoking `changeMinter` method of the contract. // ChangeMinter creates a transaction invoking `changeMinter` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) ChangeMinter(newMinter *keys.PublicKey) (util.Uint256, uint32, error) { func (c *Contract) ChangeMinter(newMinter *keys.PublicKey) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "changeMinter", newMinter) return c.actor.SendCall(c.hash, "changeMinter", newMinter)
} }
// ChangeMinterTransaction creates a transaction invoking `changeMinter` method of the contract. // ChangeMinterTransaction creates a transaction invoking `changeMinter` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) ChangeMinterTransaction(newMinter *keys.PublicKey) (*transaction.Transaction, error) { func (c *Contract) ChangeMinterTransaction(newMinter *keys.PublicKey) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "changeMinter", newMinter) return c.actor.MakeCall(c.hash, "changeMinter", newMinter)
} }
// ChangeMinterUnsigned creates a transaction invoking `changeMinter` method of the contract. // ChangeMinterUnsigned creates a transaction invoking `changeMinter` method of the contract.
@ -96,21 +113,21 @@ func (c *Contract) ChangeMinterTransaction(newMinter *keys.PublicKey) (*transact
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) ChangeMinterUnsigned(newMinter *keys.PublicKey) (*transaction.Transaction, error) { func (c *Contract) ChangeMinterUnsigned(newMinter *keys.PublicKey) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "changeMinter", nil, newMinter) return c.actor.MakeUnsignedCall(c.hash, "changeMinter", nil, newMinter)
} }
// ChangeOwner creates a transaction invoking `changeOwner` method of the contract. // ChangeOwner creates a transaction invoking `changeOwner` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) ChangeOwner(newOwner util.Uint160) (util.Uint256, uint32, error) { func (c *Contract) ChangeOwner(newOwner util.Uint160) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "changeOwner", newOwner) return c.actor.SendCall(c.hash, "changeOwner", newOwner)
} }
// ChangeOwnerTransaction creates a transaction invoking `changeOwner` method of the contract. // ChangeOwnerTransaction creates a transaction invoking `changeOwner` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) ChangeOwnerTransaction(newOwner util.Uint160) (*transaction.Transaction, error) { func (c *Contract) ChangeOwnerTransaction(newOwner util.Uint160) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "changeOwner", newOwner) return c.actor.MakeCall(c.hash, "changeOwner", newOwner)
} }
// ChangeOwnerUnsigned creates a transaction invoking `changeOwner` method of the contract. // ChangeOwnerUnsigned creates a transaction invoking `changeOwner` method of the contract.
@ -118,21 +135,21 @@ func (c *Contract) ChangeOwnerTransaction(newOwner util.Uint160) (*transaction.T
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) ChangeOwnerUnsigned(newOwner util.Uint160) (*transaction.Transaction, error) { func (c *Contract) ChangeOwnerUnsigned(newOwner util.Uint160) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "changeOwner", nil, newOwner) return c.actor.MakeUnsignedCall(c.hash, "changeOwner", nil, newOwner)
} }
// Destroy creates a transaction invoking `destroy` method of the contract. // Destroy creates a transaction invoking `destroy` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Destroy() (util.Uint256, uint32, error) { func (c *Contract) Destroy() (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "destroy") return c.actor.SendCall(c.hash, "destroy")
} }
// DestroyTransaction creates a transaction invoking `destroy` method of the contract. // DestroyTransaction creates a transaction invoking `destroy` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) DestroyTransaction() (*transaction.Transaction, error) { func (c *Contract) DestroyTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "destroy") return c.actor.MakeCall(c.hash, "destroy")
} }
// DestroyUnsigned creates a transaction invoking `destroy` method of the contract. // DestroyUnsigned creates a transaction invoking `destroy` method of the contract.
@ -140,21 +157,21 @@ func (c *Contract) DestroyTransaction() (*transaction.Transaction, error) {
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) DestroyUnsigned() (*transaction.Transaction, error) { func (c *Contract) DestroyUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "destroy", nil) return c.actor.MakeUnsignedCall(c.hash, "destroy", nil)
} }
// MaxSupply creates a transaction invoking `maxSupply` method of the contract. // MaxSupply creates a transaction invoking `maxSupply` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) MaxSupply() (util.Uint256, uint32, error) { func (c *Contract) MaxSupply() (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "maxSupply") return c.actor.SendCall(c.hash, "maxSupply")
} }
// MaxSupplyTransaction creates a transaction invoking `maxSupply` method of the contract. // MaxSupplyTransaction creates a transaction invoking `maxSupply` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) MaxSupplyTransaction() (*transaction.Transaction, error) { func (c *Contract) MaxSupplyTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "maxSupply") return c.actor.MakeCall(c.hash, "maxSupply")
} }
// MaxSupplyUnsigned creates a transaction invoking `maxSupply` method of the contract. // MaxSupplyUnsigned creates a transaction invoking `maxSupply` method of the contract.
@ -162,21 +179,21 @@ func (c *Contract) MaxSupplyTransaction() (*transaction.Transaction, error) {
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) MaxSupplyUnsigned() (*transaction.Transaction, error) { func (c *Contract) MaxSupplyUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "maxSupply", nil) return c.actor.MakeUnsignedCall(c.hash, "maxSupply", nil)
} }
// Mint creates a transaction invoking `mint` method of the contract. // Mint creates a transaction invoking `mint` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Mint(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data any) (util.Uint256, uint32, error) { func (c *Contract) Mint(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data any) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "mint", from, to, amount, swapId, signature, data) return c.actor.SendCall(c.hash, "mint", from, to, amount, swapId, signature, data)
} }
// MintTransaction creates a transaction invoking `mint` method of the contract. // MintTransaction creates a transaction invoking `mint` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) MintTransaction(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data any) (*transaction.Transaction, error) { func (c *Contract) MintTransaction(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data any) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "mint", from, to, amount, swapId, signature, data) return c.actor.MakeCall(c.hash, "mint", from, to, amount, swapId, signature, data)
} }
// MintUnsigned creates a transaction invoking `mint` method of the contract. // MintUnsigned creates a transaction invoking `mint` method of the contract.
@ -184,21 +201,21 @@ func (c *Contract) MintTransaction(from util.Uint160, to util.Uint160, amount *b
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) MintUnsigned(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data any) (*transaction.Transaction, error) { func (c *Contract) MintUnsigned(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data any) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "mint", nil, from, to, amount, swapId, signature, data) return c.actor.MakeUnsignedCall(c.hash, "mint", nil, from, to, amount, swapId, signature, data)
} }
// Update creates a transaction invoking `update` method of the contract. // Update creates a transaction invoking `update` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Update(nef []byte, manifest []byte) (util.Uint256, uint32, error) { func (c *Contract) Update(nef []byte, manifest []byte) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "update", nef, manifest) return c.actor.SendCall(c.hash, "update", nef, manifest)
} }
// UpdateTransaction creates a transaction invoking `update` method of the contract. // UpdateTransaction creates a transaction invoking `update` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) UpdateTransaction(nef []byte, manifest []byte) (*transaction.Transaction, error) { func (c *Contract) UpdateTransaction(nef []byte, manifest []byte) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "update", nef, manifest) return c.actor.MakeCall(c.hash, "update", nef, manifest)
} }
// UpdateUnsigned creates a transaction invoking `update` method of the contract. // UpdateUnsigned creates a transaction invoking `update` method of the contract.
@ -206,21 +223,21 @@ func (c *Contract) UpdateTransaction(nef []byte, manifest []byte) (*transaction.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) UpdateUnsigned(nef []byte, manifest []byte) (*transaction.Transaction, error) { func (c *Contract) UpdateUnsigned(nef []byte, manifest []byte) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "update", nil, nef, manifest) return c.actor.MakeUnsignedCall(c.hash, "update", nil, nef, manifest)
} }
// UpdateCap creates a transaction invoking `updateCap` method of the contract. // UpdateCap creates a transaction invoking `updateCap` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) UpdateCap(newCap *big.Int) (util.Uint256, uint32, error) { func (c *Contract) UpdateCap(newCap *big.Int) (util.Uint256, uint32, error) {
return c.actor.SendCall(Hash, "updateCap", newCap) return c.actor.SendCall(c.hash, "updateCap", newCap)
} }
// UpdateCapTransaction creates a transaction invoking `updateCap` method of the contract. // UpdateCapTransaction creates a transaction invoking `updateCap` method of the contract.
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) UpdateCapTransaction(newCap *big.Int) (*transaction.Transaction, error) { func (c *Contract) UpdateCapTransaction(newCap *big.Int) (*transaction.Transaction, error) {
return c.actor.MakeCall(Hash, "updateCap", newCap) return c.actor.MakeCall(c.hash, "updateCap", newCap)
} }
// UpdateCapUnsigned creates a transaction invoking `updateCap` method of the contract. // UpdateCapUnsigned creates a transaction invoking `updateCap` method of the contract.
@ -228,5 +245,95 @@ func (c *Contract) UpdateCapTransaction(newCap *big.Int) (*transaction.Transacti
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) UpdateCapUnsigned(newCap *big.Int) (*transaction.Transaction, error) { func (c *Contract) UpdateCapUnsigned(newCap *big.Int) (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(Hash, "updateCap", nil, newCap) return c.actor.MakeUnsignedCall(c.hash, "updateCap", nil, newCap)
}
// OnMintEventsFromApplicationLog retrieves a set of all emitted events
// with "OnMint" name from the provided [result.ApplicationLog].
func OnMintEventsFromApplicationLog(log *result.ApplicationLog) ([]*OnMintEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*OnMintEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "OnMint" {
continue
}
event := new(OnMintEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize OnMintEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to OnMintEvent or
// returns an error if it's not possible to do to so.
func (e *OnMintEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 4 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.From, err = func(item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field From: %w", err)
}
index++
e.To, err = func(item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field To: %w", err)
}
index++
e.Amount, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field Amount: %w", err)
}
index++
e.SwapId, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field SwapId: %w", err)
}
return nil
} }

View file

@ -1,3 +1,5 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package nonnepxxcontractwithiterators contains RPC wrappers for Non-NEPXX contract with iterators contract. // Package nonnepxxcontractwithiterators contains RPC wrappers for Non-NEPXX contract with iterators contract.
package nonnepxxcontractwithiterators package nonnepxxcontractwithiterators
@ -23,17 +25,18 @@ type Invoker interface {
// ContractReader implements safe contract methods. // ContractReader implements safe contract methods.
type ContractReader struct { type ContractReader struct {
invoker Invoker invoker Invoker
hash util.Uint160
} }
// NewReader creates an instance of ContractReader using Hash and the given Invoker. // NewReader creates an instance of ContractReader using Hash and the given Invoker.
func NewReader(invoker Invoker) *ContractReader { func NewReader(invoker Invoker) *ContractReader {
return &ContractReader{invoker} var hash = Hash
return &ContractReader{invoker, hash}
} }
// Tokens invokes `tokens` method of contract. // Tokens invokes `tokens` method of contract.
func (c *ContractReader) Tokens() (uuid.UUID, result.Iterator, error) { func (c *ContractReader) Tokens() (uuid.UUID, result.Iterator, error) {
return unwrap.SessionIterator(c.invoker.Call(Hash, "tokens")) return unwrap.SessionIterator(c.invoker.Call(c.hash, "tokens"))
} }
// TokensExpanded is similar to Tokens (uses the same contract // TokensExpanded is similar to Tokens (uses the same contract
@ -42,12 +45,12 @@ func (c *ContractReader) Tokens() (uuid.UUID, result.Iterator, error) {
// number of result items from the iterator right in the VM and return them to // number of result items from the iterator right in the VM and return them to
// you. It's only limited by VM stack and GAS available for RPC invocations. // you. It's only limited by VM stack and GAS available for RPC invocations.
func (c *ContractReader) TokensExpanded(_numOfIteratorItems int) ([]stackitem.Item, error) { func (c *ContractReader) TokensExpanded(_numOfIteratorItems int) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.CallAndExpandIterator(Hash, "tokens", _numOfIteratorItems)) return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "tokens", _numOfIteratorItems))
} }
// GetAllRecords invokes `getAllRecords` method of contract. // GetAllRecords invokes `getAllRecords` method of contract.
func (c *ContractReader) GetAllRecords(name string) (uuid.UUID, result.Iterator, error) { func (c *ContractReader) GetAllRecords(name string) (uuid.UUID, result.Iterator, error) {
return unwrap.SessionIterator(c.invoker.Call(Hash, "getAllRecords", name)) return unwrap.SessionIterator(c.invoker.Call(c.hash, "getAllRecords", name))
} }
// GetAllRecordsExpanded is similar to GetAllRecords (uses the same contract // GetAllRecordsExpanded is similar to GetAllRecords (uses the same contract
@ -56,5 +59,5 @@ func (c *ContractReader) GetAllRecords(name string) (uuid.UUID, result.Iterator,
// number of result items from the iterator right in the VM and return them to // number of result items from the iterator right in the VM and return them to
// you. It's only limited by VM stack and GAS available for RPC invocations. // you. It's only limited by VM stack and GAS available for RPC invocations.
func (c *ContractReader) GetAllRecordsExpanded(name string, _numOfIteratorItems int) ([]stackitem.Item, error) { func (c *ContractReader) GetAllRecordsExpanded(name string, _numOfIteratorItems int) ([]stackitem.Item, error) {
return unwrap.Array(c.invoker.CallAndExpandIterator(Hash, "getAllRecords", _numOfIteratorItems, name)) return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "getAllRecords", _numOfIteratorItems, name))
} }

View file

@ -0,0 +1,7 @@
package invalid1
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
func Main() {
runtime.Notify("Non declared event")
}

View file

@ -0,0 +1 @@
name: Test undeclared event

View file

@ -0,0 +1,7 @@
package invalid2
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
func Main() {
runtime.Notify("SomeEvent", "p1", "p2")
}

View file

@ -0,0 +1,6 @@
name: Test undeclared event
events:
- name: SomeEvent
parameters:
- name: p1
type: String

View file

@ -0,0 +1,7 @@
package invalid3
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
func Main() {
runtime.Notify("SomeEvent", "p1", 5)
}

View file

@ -0,0 +1,8 @@
name: Test undeclared event
events:
- name: SomeEvent
parameters:
- name: p1
type: String
- name: p2
type: String

View file

@ -0,0 +1,17 @@
package invalid4
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
type SomeStruct1 struct {
Field1 int
}
type SomeStruct2 struct {
Field2 string
}
func Main() {
// Inconsistent event params usages (different named types throughout the usages).
runtime.Notify("SomeEvent", SomeStruct1{Field1: 123})
runtime.Notify("SomeEvent", SomeStruct2{Field2: "str"})
}

View file

@ -0,0 +1,6 @@
name: Test undeclared event
events:
- name: SomeEvent
parameters:
- name: p1
type: Array

View file

@ -0,0 +1,12 @@
package invalid5
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
type NamedStruct struct {
SomeInt int
}
func Main() NamedStruct {
runtime.Notify("SomeEvent", []interface{}{123})
return NamedStruct{SomeInt: 123}
}

View file

@ -0,0 +1,16 @@
name: Test undeclared event
events:
- name: SomeEvent
parameters:
- name: p1
type: Array
extendedtype:
base: Array
name: invalid5.NamedStruct
namedtypes:
invalid5.NamedStruct:
base: Array
name: invalid5.NamedStruct
fields:
- field: SomeInt
base: Integer

View file

@ -0,0 +1,14 @@
package invalid6
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
type SomeStruct struct {
Field int
// RPC binding generator will convert this field into exported, which matches
// exactly the existing Field.
field int
}
func Main() {
runtime.Notify("SomeEvent", SomeStruct{Field: 123, field: 123})
}

View file

@ -0,0 +1,18 @@
name: Test duplicating event fields
events:
- name: SomeEvent
parameters:
- name: p1
type: Struct
extendedtype:
base: Struct
name: SomeStruct
namedtypes:
SomeStruct:
base: Struct
name: SomeStruct
fields:
- field: Field
base: Integer
- field: field
base: Integer

View file

@ -0,0 +1,14 @@
package invalid7
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
type SomeStruct struct {
Field int
// RPC binding generator will convert this field into exported, which matches
// exactly the existing Field.
field int
}
func Main() {
runtime.Notify("SomeEvent", SomeStruct{Field: 123, field: 123})
}

View file

@ -0,0 +1,6 @@
name: Test duplicating autogenerated event fields
events:
- name: SomeEvent
parameters:
- name: p1
type: Struct

View file

@ -0,0 +1,16 @@
package invalid8
type SomeStruct struct {
Field int
// RPC binding generator will convert this field into exported, which matches
// exactly the existing Field.
field int
}
func Main() SomeStruct {
s := SomeStruct{
Field: 1,
field: 2,
}
return s
}

View file

@ -0,0 +1 @@
name: Test duplicating struct fields

View file

@ -0,0 +1,23 @@
name: "Notifications"
sourceurl: https://github.com/nspcc-dev/neo-go/
events:
- name: "! complicated name %$#"
parameters:
- name: ! complicated param @#$%
type: String
- name: "SomeMap"
parameters:
- name: m
type: Map
- name: "SomeStruct"
parameters:
- name: s
type: Struct
- name: "SomeArray"
parameters:
- name: a
type: Array
- name: "SomeUnexportedField"
parameters:
- name: s
type: Struct

View file

@ -0,0 +1,60 @@
name: "Notifications"
sourceurl: https://github.com/nspcc-dev/neo-go/
events:
- name: "! complicated name %$#"
parameters:
- name: ! complicated param @#$%
type: String
- name: "SomeMap"
parameters:
- name: m
type: Map
extendedtype:
base: Map
key: Integer
value:
base: Map
key: String
value:
base: Array
value:
base: Hash160
- name: "SomeStruct"
parameters:
- name: s
type: Struct
extendedtype:
base: Struct
name: crazyStruct
- name: "SomeArray"
parameters:
- name: a
type: Array
extendedtype:
base: Array
value:
base: Array
value:
base: Integer
- name: "SomeUnexportedField"
parameters:
- name: s
type: Struct
extendedtype:
base: Struct
name: simpleStruct
namedtypes:
crazyStruct:
base: Struct
name: crazyStruct
fields:
- field: I
base: Integer
- field: B
base: Boolean
simpleStruct:
base: Struct
name: simpleStruct
fields:
- field: i
base: Integer

View file

@ -0,0 +1,23 @@
name: "Notifications"
sourceurl: https://github.com/nspcc-dev/neo-go/
events:
- name: "! complicated name %$#"
parameters:
- name: ! complicated param @#$%
type: String
- name: "SomeMap"
parameters:
- name: m
type: Map
- name: "SomeStruct"
parameters:
- name: s
type: Struct
- name: "SomeArray"
parameters:
- name: a
type: Array
- name: "SomeUnexportedField"
parameters:
- name: s
type: Struct

View file

@ -0,0 +1,33 @@
package structs
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
)
func Main() {
runtime.Notify("! complicated name %$#", "str1")
}
func CrazyMap() {
runtime.Notify("SomeMap", map[int][]map[string][]interop.Hash160{})
}
func Struct() {
runtime.Notify("SomeStruct", struct {
I int
B bool
}{I: 123, B: true})
}
func Array() {
runtime.Notify("SomeArray", [][]int{})
}
// UnexportedField emits notification with unexported field that must be converted
// to exported in the resulting RPC binding.
func UnexportedField() {
runtime.Notify("SomeUnexportedField", struct {
i int
}{i: 123})
}

View file

@ -0,0 +1,500 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package structs contains RPC wrappers for Notifications contract.
package structs
import (
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"unicode/utf8"
)
// Hash contains contract hash.
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
type ComplicatedNameEvent struct {
ComplicatedParam string
}
// SomeMapEvent represents "SomeMap" event emitted by the contract.
type SomeMapEvent struct {
M map[any]any
}
// SomeStructEvent represents "SomeStruct" event emitted by the contract.
type SomeStructEvent struct {
S []any
}
// SomeArrayEvent represents "SomeArray" event emitted by the contract.
type SomeArrayEvent struct {
A []any
}
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
type SomeUnexportedFieldEvent struct {
S []any
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
MakeRun(script []byte) (*transaction.Transaction, error)
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
SendRun(script []byte) (util.Uint256, uint32, error)
}
// Contract implements all contract methods.
type Contract struct {
actor Actor
hash util.Uint160
}
// New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract {
var hash = Hash
return &Contract{actor, hash}
}
// Array creates a transaction invoking `array` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Array() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "array")
}
// ArrayTransaction creates a transaction invoking `array` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) ArrayTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "array")
}
// ArrayUnsigned creates a transaction invoking `array` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) ArrayUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "array", nil)
}
// CrazyMap creates a transaction invoking `crazyMap` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) CrazyMap() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "crazyMap")
}
// CrazyMapTransaction creates a transaction invoking `crazyMap` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) CrazyMapTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "crazyMap")
}
// CrazyMapUnsigned creates a transaction invoking `crazyMap` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) CrazyMapUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "crazyMap", nil)
}
// Main creates a transaction invoking `main` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Main() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "main")
}
// MainTransaction creates a transaction invoking `main` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) MainTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "main")
}
// MainUnsigned creates a transaction invoking `main` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) MainUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "main", nil)
}
// Struct creates a transaction invoking `struct` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Struct() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "struct")
}
// StructTransaction creates a transaction invoking `struct` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) StructTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "struct")
}
// StructUnsigned creates a transaction invoking `struct` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
}
// UnexportedField creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) UnexportedField() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "unexportedField")
}
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "unexportedField")
}
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
}
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
// with "! complicated name %$#" name from the provided [result.ApplicationLog].
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*ComplicatedNameEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "! complicated name %$#" {
continue
}
event := new(ComplicatedNameEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize ComplicatedNameEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to ComplicatedNameEvent or
// returns an error if it's not possible to do to so.
func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.ComplicatedParam, err = func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[index])
if err != nil {
return fmt.Errorf("field ComplicatedParam: %w", err)
}
return nil
}
// SomeMapEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeMap" name from the provided [result.ApplicationLog].
func SomeMapEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeMapEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeMapEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeMap" {
continue
}
event := new(SomeMapEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeMapEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeMapEvent or
// returns an error if it's not possible to do to so.
func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.M, err = func(item stackitem.Item) (map[any]any, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[any]any)
for i := range m {
k, err := m[i].Key.Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := m[i].Value.Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field M: %w", err)
}
return nil
}
// SomeStructEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeStruct" name from the provided [result.ApplicationLog].
func SomeStructEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeStructEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeStructEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeStruct" {
continue
}
event := new(SomeStructEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeStructEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeStructEvent or
// returns an error if it's not possible to do to so.
func (e *SomeStructEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.S, err = func(item stackitem.Item) ([]any, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]any, len(arr))
for i := range res {
res[i], err = arr[i].Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field S: %w", err)
}
return nil
}
// SomeArrayEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeArray" name from the provided [result.ApplicationLog].
func SomeArrayEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeArrayEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeArrayEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeArray" {
continue
}
event := new(SomeArrayEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeArrayEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeArrayEvent or
// returns an error if it's not possible to do to so.
func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.A, err = func(item stackitem.Item) ([]any, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]any, len(arr))
for i := range res {
res[i], err = arr[i].Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field A: %w", err)
}
return nil
}
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeUnexportedFieldEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeUnexportedField" {
continue
}
event := new(SomeUnexportedFieldEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
// returns an error if it's not possible to do to so.
func (e *SomeUnexportedFieldEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.S, err = func(item stackitem.Item) ([]any, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]any, len(arr))
for i := range res {
res[i], err = arr[i].Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field S: %w", err)
}
return nil
}

View file

@ -0,0 +1,623 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package structs contains RPC wrappers for Notifications contract.
package structs
import (
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"math/big"
"unicode/utf8"
)
// Hash contains contract hash.
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
// CrazyStruct is a contract-specific crazyStruct type used by its methods.
type CrazyStruct struct {
I *big.Int
B bool
}
// SimpleStruct is a contract-specific simpleStruct type used by its methods.
type SimpleStruct struct {
I *big.Int
}
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
type ComplicatedNameEvent struct {
ComplicatedParam string
}
// SomeMapEvent represents "SomeMap" event emitted by the contract.
type SomeMapEvent struct {
M map[*big.Int]map[string][]util.Uint160
}
// SomeStructEvent represents "SomeStruct" event emitted by the contract.
type SomeStructEvent struct {
S *CrazyStruct
}
// SomeArrayEvent represents "SomeArray" event emitted by the contract.
type SomeArrayEvent struct {
A [][]*big.Int
}
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
type SomeUnexportedFieldEvent struct {
S *SimpleStruct
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
MakeRun(script []byte) (*transaction.Transaction, error)
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
SendRun(script []byte) (util.Uint256, uint32, error)
}
// Contract implements all contract methods.
type Contract struct {
actor Actor
hash util.Uint160
}
// New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract {
var hash = Hash
return &Contract{actor, hash}
}
// Array creates a transaction invoking `array` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Array() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "array")
}
// ArrayTransaction creates a transaction invoking `array` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) ArrayTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "array")
}
// ArrayUnsigned creates a transaction invoking `array` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) ArrayUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "array", nil)
}
// CrazyMap creates a transaction invoking `crazyMap` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) CrazyMap() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "crazyMap")
}
// CrazyMapTransaction creates a transaction invoking `crazyMap` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) CrazyMapTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "crazyMap")
}
// CrazyMapUnsigned creates a transaction invoking `crazyMap` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) CrazyMapUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "crazyMap", nil)
}
// Main creates a transaction invoking `main` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Main() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "main")
}
// MainTransaction creates a transaction invoking `main` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) MainTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "main")
}
// MainUnsigned creates a transaction invoking `main` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) MainUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "main", nil)
}
// Struct creates a transaction invoking `struct` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Struct() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "struct")
}
// StructTransaction creates a transaction invoking `struct` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) StructTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "struct")
}
// StructUnsigned creates a transaction invoking `struct` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
}
// UnexportedField creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) UnexportedField() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "unexportedField")
}
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "unexportedField")
}
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
}
// itemToCrazyStruct converts stack item into *CrazyStruct.
func itemToCrazyStruct(item stackitem.Item, err error) (*CrazyStruct, error) {
if err != nil {
return nil, err
}
var res = new(CrazyStruct)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of CrazyStruct from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *CrazyStruct) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 2 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
index++
res.B, err = arr[index].TryBool()
if err != nil {
return fmt.Errorf("field B: %w", err)
}
return nil
}
// itemToSimpleStruct converts stack item into *SimpleStruct.
func itemToSimpleStruct(item stackitem.Item, err error) (*SimpleStruct, error) {
if err != nil {
return nil, err
}
var res = new(SimpleStruct)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of SimpleStruct from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *SimpleStruct) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
return nil
}
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
// with "! complicated name %$#" name from the provided [result.ApplicationLog].
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*ComplicatedNameEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "! complicated name %$#" {
continue
}
event := new(ComplicatedNameEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize ComplicatedNameEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to ComplicatedNameEvent or
// returns an error if it's not possible to do to so.
func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.ComplicatedParam, err = func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[index])
if err != nil {
return fmt.Errorf("field ComplicatedParam: %w", err)
}
return nil
}
// SomeMapEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeMap" name from the provided [result.ApplicationLog].
func SomeMapEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeMapEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeMapEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeMap" {
continue
}
event := new(SomeMapEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeMapEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeMapEvent or
// returns an error if it's not possible to do to so.
func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.M, err = func(item stackitem.Item) (map[*big.Int]map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[*big.Int]map[string][]util.Uint160)
for i := range m {
k, err := m[i].Key.TryInteger()
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) (map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[string][]util.Uint160)
for i := range m {
k, err := func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Key)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
}(arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field M: %w", err)
}
return nil
}
// SomeStructEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeStruct" name from the provided [result.ApplicationLog].
func SomeStructEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeStructEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeStructEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeStruct" {
continue
}
event := new(SomeStructEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeStructEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeStructEvent or
// returns an error if it's not possible to do to so.
func (e *SomeStructEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.S, err = itemToCrazyStruct(arr[index], nil)
if err != nil {
return fmt.Errorf("field S: %w", err)
}
return nil
}
// SomeArrayEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeArray" name from the provided [result.ApplicationLog].
func SomeArrayEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeArrayEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeArrayEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeArray" {
continue
}
event := new(SomeArrayEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeArrayEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeArrayEvent or
// returns an error if it's not possible to do to so.
func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.A, err = func(item stackitem.Item) ([][]*big.Int, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([][]*big.Int, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) ([]*big.Int, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]*big.Int, len(arr))
for i := range res {
res[i], err = arr[i].TryInteger()
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field A: %w", err)
}
return nil
}
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeUnexportedFieldEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeUnexportedField" {
continue
}
event := new(SomeUnexportedFieldEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
// returns an error if it's not possible to do to so.
func (e *SomeUnexportedFieldEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.S, err = itemToSimpleStruct(arr[index], nil)
if err != nil {
return fmt.Errorf("field S: %w", err)
}
return nil
}

View file

@ -0,0 +1,636 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package structs contains RPC wrappers for Notifications contract.
package structs
import (
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"math/big"
"unicode/utf8"
)
// Hash contains contract hash.
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
// Unnamed is a contract-specific unnamed type used by its methods.
type Unnamed struct {
I *big.Int
B bool
}
// UnnamedX is a contract-specific unnamedX type used by its methods.
type UnnamedX struct {
I *big.Int
}
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
type ComplicatedNameEvent struct {
ComplicatedParam string
}
// SomeMapEvent represents "SomeMap" event emitted by the contract.
type SomeMapEvent struct {
M map[*big.Int][]map[string][]util.Uint160
}
// SomeStructEvent represents "SomeStruct" event emitted by the contract.
type SomeStructEvent struct {
S *Unnamed
}
// SomeArrayEvent represents "SomeArray" event emitted by the contract.
type SomeArrayEvent struct {
A [][]*big.Int
}
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
type SomeUnexportedFieldEvent struct {
S *UnnamedX
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
MakeRun(script []byte) (*transaction.Transaction, error)
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
SendRun(script []byte) (util.Uint256, uint32, error)
}
// Contract implements all contract methods.
type Contract struct {
actor Actor
hash util.Uint160
}
// New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract {
var hash = Hash
return &Contract{actor, hash}
}
// Array creates a transaction invoking `array` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Array() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "array")
}
// ArrayTransaction creates a transaction invoking `array` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) ArrayTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "array")
}
// ArrayUnsigned creates a transaction invoking `array` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) ArrayUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "array", nil)
}
// CrazyMap creates a transaction invoking `crazyMap` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) CrazyMap() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "crazyMap")
}
// CrazyMapTransaction creates a transaction invoking `crazyMap` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) CrazyMapTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "crazyMap")
}
// CrazyMapUnsigned creates a transaction invoking `crazyMap` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) CrazyMapUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "crazyMap", nil)
}
// Main creates a transaction invoking `main` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Main() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "main")
}
// MainTransaction creates a transaction invoking `main` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) MainTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "main")
}
// MainUnsigned creates a transaction invoking `main` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) MainUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "main", nil)
}
// Struct creates a transaction invoking `struct` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Struct() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "struct")
}
// StructTransaction creates a transaction invoking `struct` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) StructTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "struct")
}
// StructUnsigned creates a transaction invoking `struct` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
}
// UnexportedField creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) UnexportedField() (util.Uint256, uint32, error) {
return c.actor.SendCall(c.hash, "unexportedField")
}
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
return c.actor.MakeCall(c.hash, "unexportedField")
}
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` method of the contract.
// This transaction is not signed, it's simply returned to the caller.
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
}
// itemToUnnamed converts stack item into *Unnamed.
func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
if err != nil {
return nil, err
}
var res = new(Unnamed)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of Unnamed from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 2 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
index++
res.B, err = arr[index].TryBool()
if err != nil {
return fmt.Errorf("field B: %w", err)
}
return nil
}
// itemToUnnamedX converts stack item into *UnnamedX.
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
if err != nil {
return nil, err
}
var res = new(UnnamedX)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of UnnamedX from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
return nil
}
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
// with "! complicated name %$#" name from the provided [result.ApplicationLog].
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*ComplicatedNameEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "! complicated name %$#" {
continue
}
event := new(ComplicatedNameEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize ComplicatedNameEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to ComplicatedNameEvent or
// returns an error if it's not possible to do to so.
func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.ComplicatedParam, err = func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[index])
if err != nil {
return fmt.Errorf("field ComplicatedParam: %w", err)
}
return nil
}
// SomeMapEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeMap" name from the provided [result.ApplicationLog].
func SomeMapEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeMapEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeMapEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeMap" {
continue
}
event := new(SomeMapEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeMapEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeMapEvent or
// returns an error if it's not possible to do to so.
func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.M, err = func(item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[*big.Int][]map[string][]util.Uint160)
for i := range m {
k, err := m[i].Key.TryInteger()
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]map[string][]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]map[string][]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[string][]util.Uint160)
for i := range m {
k, err := func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Key)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
}(arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field M: %w", err)
}
return nil
}
// SomeStructEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeStruct" name from the provided [result.ApplicationLog].
func SomeStructEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeStructEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeStructEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeStruct" {
continue
}
event := new(SomeStructEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeStructEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeStructEvent or
// returns an error if it's not possible to do to so.
func (e *SomeStructEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.S, err = itemToUnnamed(arr[index], nil)
if err != nil {
return fmt.Errorf("field S: %w", err)
}
return nil
}
// SomeArrayEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeArray" name from the provided [result.ApplicationLog].
func SomeArrayEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeArrayEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeArrayEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeArray" {
continue
}
event := new(SomeArrayEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeArrayEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeArrayEvent or
// returns an error if it's not possible to do to so.
func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.A, err = func(item stackitem.Item) ([][]*big.Int, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([][]*big.Int, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) ([]*big.Int, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]*big.Int, len(arr))
for i := range res {
res[i], err = arr[i].TryInteger()
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field A: %w", err)
}
return nil
}
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*SomeUnexportedFieldEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "SomeUnexportedField" {
continue
}
event := new(SomeUnexportedFieldEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
// returns an error if it's not possible to do to so.
func (e *SomeUnexportedFieldEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.S, err = itemToUnnamedX(arr[index], nil)
if err != nil {
return fmt.Errorf("field S: %w", err)
}
return nil
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
package structs
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
)
type Internal struct {
Bool bool
Int int
Bytes []byte
String string
H160 interop.Hash160
H256 interop.Hash256
PK interop.PublicKey
PubKey interop.PublicKey
Sign interop.Signature
ArrOfBytes [][]byte
ArrOfH160 []interop.Hash160
Map map[int][]interop.PublicKey
Struct *Internal
unexportedField int // this one should be exported in the resulting RPC binding.
}
func Contract(mc management.Contract) management.Contract {
return mc
}
func Block(b *ledger.Block) *ledger.Block {
return b
}
func Transaction(t *ledger.Transaction) *ledger.Transaction {
return t
}
func Struct(s *Internal) *Internal {
return s
}

View file

@ -1,3 +1,3 @@
name: "Types" name: "Types"
sourceurl: https://github.com/nspcc-dev/neo-go/ sourceurl: https://github.com/nspcc-dev/neo-go/
safemethods: ["bool", "int", "bytes", "string", "any", "hash160", "hash256", "publicKey", "signature", "bools", "ints", "bytess", "strings", "hash160s", "hash256s", "publicKeys", "signatures", "aAAStrings", "maps", "crazyMaps"] safemethods: ["bool", "int", "bytes", "string", "any", "hash160", "hash256", "publicKey", "signature", "bools", "ints", "bytess", "strings", "hash160s", "hash256s", "publicKeys", "signatures", "aAAStrings", "maps", "crazyMaps", "anyMaps", "unnamedStructs", "unnamedStructsX"]

View file

@ -1,3 +1,5 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package types contains RPC wrappers for Types contract. // Package types contains RPC wrappers for Types contract.
package types package types
@ -16,6 +18,17 @@ import (
// Hash contains contract hash. // Hash contains contract hash.
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0} var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
// Unnamed is a contract-specific unnamed type used by its methods.
type Unnamed struct {
I *big.Int
}
// UnnamedX is a contract-specific unnamedX type used by its methods.
type UnnamedX struct {
I *big.Int
B bool
}
// Invoker is used by ContractReader to call various safe methods. // Invoker is used by ContractReader to call various safe methods.
type Invoker interface { type Invoker interface {
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error) Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
@ -24,42 +37,43 @@ type Invoker interface {
// ContractReader implements safe contract methods. // ContractReader implements safe contract methods.
type ContractReader struct { type ContractReader struct {
invoker Invoker invoker Invoker
hash util.Uint160
} }
// NewReader creates an instance of ContractReader using Hash and the given Invoker. // NewReader creates an instance of ContractReader using Hash and the given Invoker.
func NewReader(invoker Invoker) *ContractReader { func NewReader(invoker Invoker) *ContractReader {
return &ContractReader{invoker} var hash = Hash
return &ContractReader{invoker, hash}
} }
// AAAStrings invokes `aAAStrings` method of contract. // AAAStrings invokes `aAAStrings` method of contract.
func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) { func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
return func (item stackitem.Item, err error) ([][][]string, error) { return func(item stackitem.Item, err error) ([][][]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return func (item stackitem.Item) ([][][]string, error) { return func(item stackitem.Item) ([][][]string, error) {
arr, ok := item.Value().([]stackitem.Item) arr, ok := item.Value().([]stackitem.Item)
if !ok { if !ok {
return nil, errors.New("not an array") return nil, errors.New("not an array")
} }
res := make([][][]string, len(arr)) res := make([][][]string, len(arr))
for i := range res { for i := range res {
res[i], err = func (item stackitem.Item) ([][]string, error) { res[i], err = func(item stackitem.Item) ([][]string, error) {
arr, ok := item.Value().([]stackitem.Item) arr, ok := item.Value().([]stackitem.Item)
if !ok { if !ok {
return nil, errors.New("not an array") return nil, errors.New("not an array")
} }
res := make([][]string, len(arr)) res := make([][]string, len(arr))
for i := range res { for i := range res {
res[i], err = func (item stackitem.Item) ([]string, error) { res[i], err = func(item stackitem.Item) ([]string, error) {
arr, ok := item.Value().([]stackitem.Item) arr, ok := item.Value().([]stackitem.Item)
if !ok { if !ok {
return nil, errors.New("not an array") return nil, errors.New("not an array")
} }
res := make([]string, len(arr)) res := make([]string, len(arr))
for i := range res { for i := range res {
res[i], err = func (item stackitem.Item) (string, error) { res[i], err = func(item stackitem.Item) (string, error) {
b, err := item.TryBytes() b, err := item.TryBytes()
if err != nil { if err != nil {
return "", err return "", err
@ -68,65 +82,93 @@ func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
return "", errors.New("not a UTF-8 string") return "", errors.New("not a UTF-8 string")
} }
return string(b), nil return string(b), nil
} (arr[i]) }(arr[i])
if err != nil { if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err) return nil, fmt.Errorf("item %d: %w", i, err)
} }
} }
return res, nil return res, nil
} (arr[i]) }(arr[i])
if err != nil { if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err) return nil, fmt.Errorf("item %d: %w", i, err)
} }
} }
return res, nil return res, nil
} (arr[i]) }(arr[i])
if err != nil { if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err) return nil, fmt.Errorf("item %d: %w", i, err)
} }
} }
return res, nil return res, nil
} (item) }(item)
} (unwrap.Item(c.invoker.Call(Hash, "aAAStrings", s))) }(unwrap.Item(c.invoker.Call(c.hash, "aAAStrings", s)))
} }
// Any invokes `any` method of contract. // Any invokes `any` method of contract.
func (c *ContractReader) Any(a any) (any, error) { func (c *ContractReader) Any(a any) (any, error) {
return func (item stackitem.Item, err error) (any, error) { return func(item stackitem.Item, err error) (any, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return item.Value(), nil return item.Value(), error(nil)
} (unwrap.Item(c.invoker.Call(Hash, "any", a))) }(unwrap.Item(c.invoker.Call(c.hash, "any", a)))
}
// AnyMaps invokes `anyMaps` method of contract.
func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
return func(item stackitem.Item, err error) (map[*big.Int]any, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) (map[*big.Int]any, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[*big.Int]any)
for i := range m {
k, err := m[i].Key.TryInteger()
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := m[i].Value.Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
} }
// Bool invokes `bool` method of contract. // Bool invokes `bool` method of contract.
func (c *ContractReader) Bool(b bool) (bool, error) { func (c *ContractReader) Bool(b bool) (bool, error) {
return unwrap.Bool(c.invoker.Call(Hash, "bool", b)) return unwrap.Bool(c.invoker.Call(c.hash, "bool", b))
} }
// Bools invokes `bools` method of contract. // Bools invokes `bools` method of contract.
func (c *ContractReader) Bools(b []bool) ([]bool, error) { func (c *ContractReader) Bools(b []bool) ([]bool, error) {
return unwrap.ArrayOfBools(c.invoker.Call(Hash, "bools", b)) return unwrap.ArrayOfBools(c.invoker.Call(c.hash, "bools", b))
} }
// Bytes invokes `bytes` method of contract. // Bytes invokes `bytes` method of contract.
func (c *ContractReader) Bytes(b []byte) ([]byte, error) { func (c *ContractReader) Bytes(b []byte) ([]byte, error) {
return unwrap.Bytes(c.invoker.Call(Hash, "bytes", b)) return unwrap.Bytes(c.invoker.Call(c.hash, "bytes", b))
} }
// Bytess invokes `bytess` method of contract. // Bytess invokes `bytess` method of contract.
func (c *ContractReader) Bytess(b [][]byte) ([][]byte, error) { func (c *ContractReader) Bytess(b [][]byte) ([][]byte, error) {
return unwrap.ArrayOfBytes(c.invoker.Call(Hash, "bytess", b)) return unwrap.ArrayOfBytes(c.invoker.Call(c.hash, "bytess", b))
} }
// CrazyMaps invokes `crazyMaps` method of contract. // CrazyMaps invokes `crazyMaps` method of contract.
func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (map[*big.Int][]map[string][]util.Uint160, error) { func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (map[*big.Int][]map[string][]util.Uint160, error) {
return func (item stackitem.Item, err error) (map[*big.Int][]map[string][]util.Uint160, error) { return func(item stackitem.Item, err error) (map[*big.Int][]map[string][]util.Uint160, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return func (item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) { return func(item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement) m, ok := item.Value().([]stackitem.MapElement)
if !ok { if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String()) return nil, fmt.Errorf("%s is not a map", item.Type().String())
@ -137,21 +179,21 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
if err != nil { if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err) return nil, fmt.Errorf("key %d: %w", i, err)
} }
v, err := func (item stackitem.Item) ([]map[string][]util.Uint160, error) { v, err := func(item stackitem.Item) ([]map[string][]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item) arr, ok := item.Value().([]stackitem.Item)
if !ok { if !ok {
return nil, errors.New("not an array") return nil, errors.New("not an array")
} }
res := make([]map[string][]util.Uint160, len(arr)) res := make([]map[string][]util.Uint160, len(arr))
for i := range res { for i := range res {
res[i], err = func (item stackitem.Item) (map[string][]util.Uint160, error) { res[i], err = func(item stackitem.Item) (map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement) m, ok := item.Value().([]stackitem.MapElement)
if !ok { if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String()) return nil, fmt.Errorf("%s is not a map", item.Type().String())
} }
res := make(map[string][]util.Uint160) res := make(map[string][]util.Uint160)
for i := range m { for i := range m {
k, err := func (item stackitem.Item) (string, error) { k, err := func(item stackitem.Item) (string, error) {
b, err := item.TryBytes() b, err := item.TryBytes()
if err != nil { if err != nil {
return "", err return "", err
@ -160,18 +202,18 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
return "", errors.New("not a UTF-8 string") return "", errors.New("not a UTF-8 string")
} }
return string(b), nil return string(b), nil
} (m[i].Key) }(m[i].Key)
if err != nil { if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err) return nil, fmt.Errorf("key %d: %w", i, err)
} }
v, err := func (item stackitem.Item) ([]util.Uint160, error) { v, err := func(item stackitem.Item) ([]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item) arr, ok := item.Value().([]stackitem.Item)
if !ok { if !ok {
return nil, errors.New("not an array") return nil, errors.New("not an array")
} }
res := make([]util.Uint160, len(arr)) res := make([]util.Uint160, len(arr))
for i := range res { for i := range res {
res[i], err = func (item stackitem.Item) (util.Uint160, error) { res[i], err = func(item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes() b, err := item.TryBytes()
if err != nil { if err != nil {
return util.Uint160{}, err return util.Uint160{}, err
@ -181,80 +223,80 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
return util.Uint160{}, err return util.Uint160{}, err
} }
return u, nil return u, nil
} (arr[i]) }(arr[i])
if err != nil { if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err) return nil, fmt.Errorf("item %d: %w", i, err)
} }
} }
return res, nil return res, nil
} (m[i].Value) }(m[i].Value)
if err != nil { if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err) return nil, fmt.Errorf("value %d: %w", i, err)
} }
res[k] = v res[k] = v
} }
return res, nil return res, nil
} (arr[i]) }(arr[i])
if err != nil { if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err) return nil, fmt.Errorf("item %d: %w", i, err)
} }
} }
return res, nil return res, nil
} (m[i].Value) }(m[i].Value)
if err != nil { if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err) return nil, fmt.Errorf("value %d: %w", i, err)
} }
res[k] = v res[k] = v
} }
return res, nil return res, nil
} (item) }(item)
} (unwrap.Item(c.invoker.Call(Hash, "crazyMaps", m))) }(unwrap.Item(c.invoker.Call(c.hash, "crazyMaps", m)))
} }
// Hash160 invokes `hash160` method of contract. // Hash160 invokes `hash160` method of contract.
func (c *ContractReader) Hash160(h util.Uint160) (util.Uint160, error) { func (c *ContractReader) Hash160(h util.Uint160) (util.Uint160, error) {
return unwrap.Uint160(c.invoker.Call(Hash, "hash160", h)) return unwrap.Uint160(c.invoker.Call(c.hash, "hash160", h))
} }
// Hash160s invokes `hash160s` method of contract. // Hash160s invokes `hash160s` method of contract.
func (c *ContractReader) Hash160s(h []util.Uint160) ([]util.Uint160, error) { func (c *ContractReader) Hash160s(h []util.Uint160) ([]util.Uint160, error) {
return unwrap.ArrayOfUint160(c.invoker.Call(Hash, "hash160s", h)) return unwrap.ArrayOfUint160(c.invoker.Call(c.hash, "hash160s", h))
} }
// Hash256 invokes `hash256` method of contract. // Hash256 invokes `hash256` method of contract.
func (c *ContractReader) Hash256(h util.Uint256) (util.Uint256, error) { func (c *ContractReader) Hash256(h util.Uint256) (util.Uint256, error) {
return unwrap.Uint256(c.invoker.Call(Hash, "hash256", h)) return unwrap.Uint256(c.invoker.Call(c.hash, "hash256", h))
} }
// Hash256s invokes `hash256s` method of contract. // Hash256s invokes `hash256s` method of contract.
func (c *ContractReader) Hash256s(h []util.Uint256) ([]util.Uint256, error) { func (c *ContractReader) Hash256s(h []util.Uint256) ([]util.Uint256, error) {
return unwrap.ArrayOfUint256(c.invoker.Call(Hash, "hash256s", h)) return unwrap.ArrayOfUint256(c.invoker.Call(c.hash, "hash256s", h))
} }
// Int invokes `int` method of contract. // Int invokes `int` method of contract.
func (c *ContractReader) Int(i *big.Int) (*big.Int, error) { func (c *ContractReader) Int(i *big.Int) (*big.Int, error) {
return unwrap.BigInt(c.invoker.Call(Hash, "int", i)) return unwrap.BigInt(c.invoker.Call(c.hash, "int", i))
} }
// Ints invokes `ints` method of contract. // Ints invokes `ints` method of contract.
func (c *ContractReader) Ints(i []*big.Int) ([]*big.Int, error) { func (c *ContractReader) Ints(i []*big.Int) ([]*big.Int, error) {
return unwrap.ArrayOfBigInts(c.invoker.Call(Hash, "ints", i)) return unwrap.ArrayOfBigInts(c.invoker.Call(c.hash, "ints", i))
} }
// Maps invokes `maps` method of contract. // Maps invokes `maps` method of contract.
func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) { func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
return func (item stackitem.Item, err error) (map[string]string, error) { return func(item stackitem.Item, err error) (map[string]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return func (item stackitem.Item) (map[string]string, error) { return func(item stackitem.Item) (map[string]string, error) {
m, ok := item.Value().([]stackitem.MapElement) m, ok := item.Value().([]stackitem.MapElement)
if !ok { if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String()) return nil, fmt.Errorf("%s is not a map", item.Type().String())
} }
res := make(map[string]string) res := make(map[string]string)
for i := range m { for i := range m {
k, err := func (item stackitem.Item) (string, error) { k, err := func(item stackitem.Item) (string, error) {
b, err := item.TryBytes() b, err := item.TryBytes()
if err != nil { if err != nil {
return "", err return "", err
@ -263,11 +305,11 @@ func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
return "", errors.New("not a UTF-8 string") return "", errors.New("not a UTF-8 string")
} }
return string(b), nil return string(b), nil
} (m[i].Key) }(m[i].Key)
if err != nil { if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err) return nil, fmt.Errorf("key %d: %w", i, err)
} }
v, err := func (item stackitem.Item) (string, error) { v, err := func(item stackitem.Item) (string, error) {
b, err := item.TryBytes() b, err := item.TryBytes()
if err != nil { if err != nil {
return "", err return "", err
@ -276,43 +318,127 @@ func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
return "", errors.New("not a UTF-8 string") return "", errors.New("not a UTF-8 string")
} }
return string(b), nil return string(b), nil
} (m[i].Value) }(m[i].Value)
if err != nil { if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err) return nil, fmt.Errorf("value %d: %w", i, err)
} }
res[k] = v res[k] = v
} }
return res, nil return res, nil
} (item) }(item)
} (unwrap.Item(c.invoker.Call(Hash, "maps", m))) }(unwrap.Item(c.invoker.Call(c.hash, "maps", m)))
} }
// PublicKey invokes `publicKey` method of contract. // PublicKey invokes `publicKey` method of contract.
func (c *ContractReader) PublicKey(k *keys.PublicKey) (*keys.PublicKey, error) { func (c *ContractReader) PublicKey(k *keys.PublicKey) (*keys.PublicKey, error) {
return unwrap.PublicKey(c.invoker.Call(Hash, "publicKey", k)) return unwrap.PublicKey(c.invoker.Call(c.hash, "publicKey", k))
} }
// PublicKeys invokes `publicKeys` method of contract. // PublicKeys invokes `publicKeys` method of contract.
func (c *ContractReader) PublicKeys(k keys.PublicKeys) (keys.PublicKeys, error) { func (c *ContractReader) PublicKeys(k keys.PublicKeys) (keys.PublicKeys, error) {
return unwrap.ArrayOfPublicKeys(c.invoker.Call(Hash, "publicKeys", k)) return unwrap.ArrayOfPublicKeys(c.invoker.Call(c.hash, "publicKeys", k))
} }
// Signature invokes `signature` method of contract. // Signature invokes `signature` method of contract.
func (c *ContractReader) Signature(s []byte) ([]byte, error) { func (c *ContractReader) Signature(s []byte) ([]byte, error) {
return unwrap.Bytes(c.invoker.Call(Hash, "signature", s)) return unwrap.Bytes(c.invoker.Call(c.hash, "signature", s))
} }
// Signatures invokes `signatures` method of contract. // Signatures invokes `signatures` method of contract.
func (c *ContractReader) Signatures(s [][]byte) ([][]byte, error) { func (c *ContractReader) Signatures(s [][]byte) ([][]byte, error) {
return unwrap.ArrayOfBytes(c.invoker.Call(Hash, "signatures", s)) return unwrap.ArrayOfBytes(c.invoker.Call(c.hash, "signatures", s))
} }
// String invokes `string` method of contract. // String invokes `string` method of contract.
func (c *ContractReader) String(s string) (string, error) { func (c *ContractReader) String(s string) (string, error) {
return unwrap.UTF8String(c.invoker.Call(Hash, "string", s)) return unwrap.UTF8String(c.invoker.Call(c.hash, "string", s))
} }
// Strings invokes `strings` method of contract. // Strings invokes `strings` method of contract.
func (c *ContractReader) Strings(s []string) ([]string, error) { func (c *ContractReader) Strings(s []string) ([]string, error) {
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(Hash, "strings", s)) return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
}
// UnnamedStructs invokes `unnamedStructs` method of contract.
func (c *ContractReader) UnnamedStructs() (*Unnamed, error) {
return itemToUnnamed(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructs")))
}
// UnnamedStructsX invokes `unnamedStructsX` method of contract.
func (c *ContractReader) UnnamedStructsX() (*UnnamedX, error) {
return itemToUnnamedX(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructsX")))
}
// itemToUnnamed converts stack item into *Unnamed.
func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
if err != nil {
return nil, err
}
var res = new(Unnamed)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of Unnamed from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
return nil
}
// itemToUnnamedX converts stack item into *UnnamedX.
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
if err != nil {
return nil, err
}
var res = new(UnnamedX)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of UnnamedX from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 2 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
index++
res.B, err = arr[index].TryBool()
if err != nil {
return fmt.Errorf("field B: %w", err)
}
return nil
} }

View file

@ -0,0 +1,440 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package types contains RPC wrappers for Types contract.
package types
import (
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"math/big"
"unicode/utf8"
)
// Unnamed is a contract-specific unnamed type used by its methods.
type Unnamed struct {
I *big.Int
}
// UnnamedX is a contract-specific unnamedX type used by its methods.
type UnnamedX struct {
I *big.Int
B bool
}
// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
}
// ContractReader implements safe contract methods.
type ContractReader struct {
invoker Invoker
hash util.Uint160
}
// NewReader creates an instance of ContractReader using provided contract hash and the given Invoker.
func NewReader(invoker Invoker, hash util.Uint160) *ContractReader {
return &ContractReader{invoker, hash}
}
// AAAStrings invokes `aAAStrings` method of contract.
func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
return func(item stackitem.Item, err error) ([][][]string, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) ([][][]string, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([][][]string, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) ([][]string, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([][]string, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) ([]string, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]string, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "aAAStrings", s)))
}
// Any invokes `any` method of contract.
func (c *ContractReader) Any(a any) (any, error) {
return func(item stackitem.Item, err error) (any, error) {
if err != nil {
return nil, err
}
return item.Value(), error(nil)
}(unwrap.Item(c.invoker.Call(c.hash, "any", a)))
}
// AnyMaps invokes `anyMaps` method of contract.
func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
return func(item stackitem.Item, err error) (map[*big.Int]any, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) (map[*big.Int]any, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[*big.Int]any)
for i := range m {
k, err := m[i].Key.TryInteger()
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := m[i].Value.Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
}
// Bool invokes `bool` method of contract.
func (c *ContractReader) Bool(b bool) (bool, error) {
return unwrap.Bool(c.invoker.Call(c.hash, "bool", b))
}
// Bools invokes `bools` method of contract.
func (c *ContractReader) Bools(b []bool) ([]bool, error) {
return unwrap.ArrayOfBools(c.invoker.Call(c.hash, "bools", b))
}
// Bytes invokes `bytes` method of contract.
func (c *ContractReader) Bytes(b []byte) ([]byte, error) {
return unwrap.Bytes(c.invoker.Call(c.hash, "bytes", b))
}
// Bytess invokes `bytess` method of contract.
func (c *ContractReader) Bytess(b [][]byte) ([][]byte, error) {
return unwrap.ArrayOfBytes(c.invoker.Call(c.hash, "bytess", b))
}
// CrazyMaps invokes `crazyMaps` method of contract.
func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (map[*big.Int][]map[string][]util.Uint160, error) {
return func(item stackitem.Item, err error) (map[*big.Int][]map[string][]util.Uint160, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[*big.Int][]map[string][]util.Uint160)
for i := range m {
k, err := m[i].Key.TryInteger()
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]map[string][]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]map[string][]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (map[string][]util.Uint160, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[string][]util.Uint160)
for i := range m {
k, err := func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Key)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) ([]util.Uint160, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]util.Uint160, len(arr))
for i := range res {
res[i], err = func(item stackitem.Item) (util.Uint160, error) {
b, err := item.TryBytes()
if err != nil {
return util.Uint160{}, err
}
u, err := util.Uint160DecodeBytesBE(b)
if err != nil {
return util.Uint160{}, err
}
return u, nil
}(arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(arr[i])
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "crazyMaps", m)))
}
// Hash160 invokes `hash160` method of contract.
func (c *ContractReader) Hash160(h util.Uint160) (util.Uint160, error) {
return unwrap.Uint160(c.invoker.Call(c.hash, "hash160", h))
}
// Hash160s invokes `hash160s` method of contract.
func (c *ContractReader) Hash160s(h []util.Uint160) ([]util.Uint160, error) {
return unwrap.ArrayOfUint160(c.invoker.Call(c.hash, "hash160s", h))
}
// Hash256 invokes `hash256` method of contract.
func (c *ContractReader) Hash256(h util.Uint256) (util.Uint256, error) {
return unwrap.Uint256(c.invoker.Call(c.hash, "hash256", h))
}
// Hash256s invokes `hash256s` method of contract.
func (c *ContractReader) Hash256s(h []util.Uint256) ([]util.Uint256, error) {
return unwrap.ArrayOfUint256(c.invoker.Call(c.hash, "hash256s", h))
}
// Int invokes `int` method of contract.
func (c *ContractReader) Int(i *big.Int) (*big.Int, error) {
return unwrap.BigInt(c.invoker.Call(c.hash, "int", i))
}
// Ints invokes `ints` method of contract.
func (c *ContractReader) Ints(i []*big.Int) ([]*big.Int, error) {
return unwrap.ArrayOfBigInts(c.invoker.Call(c.hash, "ints", i))
}
// Maps invokes `maps` method of contract.
func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
return func(item stackitem.Item, err error) (map[string]string, error) {
if err != nil {
return nil, err
}
return func(item stackitem.Item) (map[string]string, error) {
m, ok := item.Value().([]stackitem.MapElement)
if !ok {
return nil, fmt.Errorf("%s is not a map", item.Type().String())
}
res := make(map[string]string)
for i := range m {
k, err := func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Key)
if err != nil {
return nil, fmt.Errorf("key %d: %w", i, err)
}
v, err := func(item stackitem.Item) (string, error) {
b, err := item.TryBytes()
if err != nil {
return "", err
}
if !utf8.Valid(b) {
return "", errors.New("not a UTF-8 string")
}
return string(b), nil
}(m[i].Value)
if err != nil {
return nil, fmt.Errorf("value %d: %w", i, err)
}
res[k] = v
}
return res, nil
}(item)
}(unwrap.Item(c.invoker.Call(c.hash, "maps", m)))
}
// PublicKey invokes `publicKey` method of contract.
func (c *ContractReader) PublicKey(k *keys.PublicKey) (*keys.PublicKey, error) {
return unwrap.PublicKey(c.invoker.Call(c.hash, "publicKey", k))
}
// PublicKeys invokes `publicKeys` method of contract.
func (c *ContractReader) PublicKeys(k keys.PublicKeys) (keys.PublicKeys, error) {
return unwrap.ArrayOfPublicKeys(c.invoker.Call(c.hash, "publicKeys", k))
}
// Signature invokes `signature` method of contract.
func (c *ContractReader) Signature(s []byte) ([]byte, error) {
return unwrap.Bytes(c.invoker.Call(c.hash, "signature", s))
}
// Signatures invokes `signatures` method of contract.
func (c *ContractReader) Signatures(s [][]byte) ([][]byte, error) {
return unwrap.ArrayOfBytes(c.invoker.Call(c.hash, "signatures", s))
}
// String invokes `string` method of contract.
func (c *ContractReader) String(s string) (string, error) {
return unwrap.UTF8String(c.invoker.Call(c.hash, "string", s))
}
// Strings invokes `strings` method of contract.
func (c *ContractReader) Strings(s []string) ([]string, error) {
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
}
// UnnamedStructs invokes `unnamedStructs` method of contract.
func (c *ContractReader) UnnamedStructs() (*Unnamed, error) {
return itemToUnnamed(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructs")))
}
// UnnamedStructsX invokes `unnamedStructsX` method of contract.
func (c *ContractReader) UnnamedStructsX() (*UnnamedX, error) {
return itemToUnnamedX(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructsX")))
}
// itemToUnnamed converts stack item into *Unnamed.
func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
if err != nil {
return nil, err
}
var res = new(Unnamed)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of Unnamed from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
return nil
}
// itemToUnnamedX converts stack item into *UnnamedX.
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
if err != nil {
return nil, err
}
var res = new(UnnamedX)
err = res.FromStackItem(item)
return res, err
}
// FromStackItem retrieves fields of UnnamedX from the given
// [stackitem.Item] or returns an error if it's not possible to do to so.
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 2 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
res.I, err = arr[index].TryInteger()
if err != nil {
return fmt.Errorf("field I: %w", err)
}
index++
res.B, err = arr[index].TryBool()
if err != nil {
return fmt.Errorf("field B: %w", err)
}
return nil
}

View file

@ -83,3 +83,21 @@ func Maps(m map[string]string) map[string]string {
func CrazyMaps(m map[int][]map[string][]interop.Hash160) map[int][]map[string][]interop.Hash160 { func CrazyMaps(m map[int][]map[string][]interop.Hash160) map[int][]map[string][]interop.Hash160 {
return m return m
} }
func AnyMaps(m map[int]any) map[int]any {
return m
}
func UnnamedStructs() struct{ I int } {
return struct{ I int }{I: 123}
}
func UnnamedStructsX() struct {
I int
B bool
} {
return struct {
I int
B bool
}{I: 123, B: true}
}

View file

@ -1,39 +0,0 @@
package structs
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
)
type Internal struct {
Bool bool
Int int
Bytes []byte
String string
H160 interop.Hash160
H256 interop.Hash256
PK interop.PublicKey
PubKey interop.PublicKey
Sign interop.Signature
ArrOfBytes [][]byte
ArrOfH160 []interop.Hash160
Map map[int][]interop.PublicKey
Struct *Internal
}
func Contract(mc management.Contract) management.Contract {
return mc
}
func Block(b *ledger.Block) *ledger.Block {
return b
}
func Transaction(t *ledger.Transaction) *ledger.Transaction {
return t
}
func Struct(s *Internal) *Internal {
return s
}

297
cli/smartcontract/testdata/verify.bindings.yml vendored Executable file
View file

@ -0,0 +1,297 @@
package: testdata
hash: "0x0000000000000000000000000000000000000000"
overrides:
burnGas.gas: int
call: any
call.args: '[]any'
call.f: any
call.method: string
call.scriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
callWithToken: any
callWithToken.args: '[]any'
callWithToken.flags: int
callWithToken.method: string
callWithToken.scriptHash: string
callWithTokenNoRet.args: '[]any'
callWithTokenNoRet.flags: int
callWithTokenNoRet.method: string
callWithTokenNoRet.scriptHash: string
checkWitness: bool
checkWitness.hashOrKey: '[]byte'
createMultisigAccount: '[]byte'
createMultisigAccount.m: int
createMultisigAccount.pubs: '[]github.com/nspcc-dev/neo-go/pkg/interop.PublicKey'
createStandardAccount: '[]byte'
createStandardAccount.pub: github.com/nspcc-dev/neo-go/pkg/interop.PublicKey
currentHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
currentIndex: int
currentSigners: '[]github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.TransactionSigner'
equals: bool
equals.b: any
gasLeft: int
getAddressVersion: int
getBlock: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Block'
getBlock.indexOrHash: any
getCallFlags: any
getCallingScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
getEntryScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
getExecutingScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
getInvocationCounter: int
getNetwork: int
getNotifications: '[][]any'
getNotifications.h: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
getRandom: int
getScriptContainer: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
getTime: int
getTransaction: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
getTransaction.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
getTransactionFromBlock: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
getTransactionFromBlock.indexOrHash: any
getTransactionFromBlock.txIndex: int
getTransactionHeight: int
getTransactionHeight.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
getTransactionSigners: '[]github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.TransactionSigner'
getTransactionSigners.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
getTransactionVMState: int
getTransactionVMState.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
getTrigger: int
loadScript: any
loadScript.args: '[]any'
loadScript.f: any
loadScript.script: '[]byte'
log.message: string
notify.args: '[]any'
notify.name: string
onNEP11Payment.amount: int
onNEP11Payment.data: any
onNEP11Payment.from: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
onNEP11Payment.token: '[]byte'
onNEP17Payment.amount: int
onNEP17Payment.data: any
onNEP17Payment.from: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
opcode0NoReturn.op: string
opcode1: any
opcode1NoReturn.arg: any
opcode1NoReturn.op: string
opcode1.arg: any
opcode1.op: string
opcode2: any
opcode2NoReturn.arg1: any
opcode2NoReturn.arg2: any
opcode2NoReturn.op: string
opcode2.arg1: any
opcode2.arg2: any
opcode2.op: string
opcode3: any
opcode3.arg1: any
opcode3.arg2: any
opcode3.arg3: any
opcode3.op: string
platform: '[]byte'
syscall0: any
syscall0NoReturn.name: string
syscall0.name: string
syscall1: any
syscall1NoReturn.arg: any
syscall1NoReturn.name: string
syscall1.arg: any
syscall1.name: string
syscall2: any
syscall2NoReturn.arg1: any
syscall2NoReturn.arg2: any
syscall2NoReturn.name: string
syscall2.arg1: any
syscall2.arg2: any
syscall2.name: string
syscall3: any
syscall3NoReturn.arg1: any
syscall3NoReturn.arg2: any
syscall3NoReturn.arg3: any
syscall3NoReturn.name: string
syscall3.arg1: any
syscall3.arg2: any
syscall3.arg3: any
syscall3.name: string
syscall4: any
syscall4NoReturn.arg1: any
syscall4NoReturn.arg2: any
syscall4NoReturn.arg3: any
syscall4NoReturn.arg4: any
syscall4NoReturn.name: string
syscall4.arg1: any
syscall4.arg2: any
syscall4.arg3: any
syscall4.arg4: any
syscall4.name: string
toBlockSR: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.BlockSR'
verify: bool
namedtypes:
ledger.Block:
base: Array
name: ledger.Block
fields:
- field: Hash
base: Hash256
- field: Version
base: Integer
- field: PrevHash
base: Hash256
- field: MerkleRoot
base: Hash256
- field: Timestamp
base: Integer
- field: Nonce
base: Integer
- field: Index
base: Integer
- field: NextConsensus
base: Hash160
- field: TransactionsLength
base: Integer
ledger.BlockSR:
base: Array
name: ledger.BlockSR
fields:
- field: Hash
base: Hash256
- field: Version
base: Integer
- field: PrevHash
base: Hash256
- field: MerkleRoot
base: Hash256
- field: Timestamp
base: Integer
- field: Nonce
base: Integer
- field: Index
base: Integer
- field: NextConsensus
base: Hash160
- field: TransactionsLength
base: Integer
- field: PrevStateRoot
base: Hash256
ledger.Transaction:
base: Array
name: ledger.Transaction
fields:
- field: Hash
base: Hash256
- field: Version
base: Integer
- field: Nonce
base: Integer
- field: Sender
base: Hash160
- field: SysFee
base: Integer
- field: NetFee
base: Integer
- field: ValidUntilBlock
base: Integer
- field: Script
base: ByteArray
ledger.TransactionSigner:
base: Array
name: ledger.TransactionSigner
fields:
- field: Account
base: Hash160
- field: Scopes
base: Integer
- field: AllowedContracts
base: Array
value:
base: Hash160
- field: AllowedGroups
base: Array
value:
base: PublicKey
- field: Rules
base: Array
value:
base: Array
name: ledger.WitnessRule
ledger.WitnessCondition:
base: Array
name: ledger.WitnessCondition
fields:
- field: Type
base: Integer
- field: Value
base: Any
ledger.WitnessRule:
base: Array
name: ledger.WitnessRule
fields:
- field: Action
base: Integer
- field: Condition
base: Array
name: ledger.WitnessCondition
types:
call.args:
base: Array
value:
base: Any
call.f:
base: InteropInterface
interface: iterator
callWithToken.args:
base: Array
value:
base: Any
callWithTokenNoRet.args:
base: Array
value:
base: Any
createMultisigAccount.pubs:
base: Array
value:
base: PublicKey
currentSigners:
base: Array
value:
base: Array
name: ledger.TransactionSigner
getBlock:
base: Array
name: ledger.Block
getCallFlags:
base: InteropInterface
interface: iterator
getNotifications:
base: Array
value:
base: Array
value:
base: Any
getScriptContainer:
base: Array
name: ledger.Transaction
getTransaction:
base: Array
name: ledger.Transaction
getTransactionFromBlock:
base: Array
name: ledger.Transaction
getTransactionSigners:
base: Array
value:
base: Array
name: ledger.TransactionSigner
loadScript.args:
base: Array
value:
base: Any
loadScript.f:
base: InteropInterface
interface: iterator
notify.args:
base: Array
value:
base: Any
toBlockSR:
base: Array
name: ledger.BlockSR

View file

@ -1,15 +1,26 @@
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
// Package verify contains RPC wrappers for verify contract. // Package verify contains RPC wrappers for verify contract.
package verify package verify
import ( import (
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
// Hash contains contract hash. // Hash contains contract hash.
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0} var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
// HelloWorldEvent represents "Hello world!" event emitted by the contract.
type HelloWorldEvent struct {
Args []any
}
// Actor is used by Contract to call state-changing methods. // Actor is used by Contract to call state-changing methods.
type Actor interface { type Actor interface {
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error) MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
@ -23,23 +34,24 @@ type Actor interface {
// Contract implements all contract methods. // Contract implements all contract methods.
type Contract struct { type Contract struct {
actor Actor actor Actor
hash util.Uint160
} }
// New creates an instance of Contract using Hash and the given Actor. // New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract { func New(actor Actor) *Contract {
return &Contract{actor} var hash = Hash
return &Contract{actor, hash}
} }
func (c *Contract) scriptForVerify() ([]byte, error) {
func scriptForVerify() ([]byte, error) { return smartcontract.CreateCallWithAssertScript(c.hash, "verify")
return smartcontract.CreateCallWithAssertScript(Hash, "verify")
} }
// Verify creates a transaction invoking `verify` method of the contract. // Verify creates a transaction invoking `verify` method of the contract.
// This transaction is signed and immediately sent to the network. // This transaction is signed and immediately sent to the network.
// The values returned are its hash, ValidUntilBlock value and error if any. // The values returned are its hash, ValidUntilBlock value and error if any.
func (c *Contract) Verify() (util.Uint256, uint32, error) { func (c *Contract) Verify() (util.Uint256, uint32, error) {
script, err := scriptForVerify() script, err := c.scriptForVerify()
if err != nil { if err != nil {
return util.Uint256{}, 0, err return util.Uint256{}, 0, err
} }
@ -50,7 +62,7 @@ func (c *Contract) Verify() (util.Uint256, uint32, error) {
// This transaction is signed, but not sent to the network, instead it's // This transaction is signed, but not sent to the network, instead it's
// returned to the caller. // returned to the caller.
func (c *Contract) VerifyTransaction() (*transaction.Transaction, error) { func (c *Contract) VerifyTransaction() (*transaction.Transaction, error) {
script, err := scriptForVerify() script, err := c.scriptForVerify()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -62,9 +74,74 @@ func (c *Contract) VerifyTransaction() (*transaction.Transaction, error) {
// Any fields of it that do not affect fees can be changed (ValidUntilBlock, // Any fields of it that do not affect fees can be changed (ValidUntilBlock,
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. // Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
func (c *Contract) VerifyUnsigned() (*transaction.Transaction, error) { func (c *Contract) VerifyUnsigned() (*transaction.Transaction, error) {
script, err := scriptForVerify() script, err := c.scriptForVerify()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return c.actor.MakeUnsignedRun(script, nil) return c.actor.MakeUnsignedRun(script, nil)
} }
// HelloWorldEventsFromApplicationLog retrieves a set of all emitted events
// with "Hello world!" name from the provided [result.ApplicationLog].
func HelloWorldEventsFromApplicationLog(log *result.ApplicationLog) ([]*HelloWorldEvent, error) {
if log == nil {
return nil, errors.New("nil application log")
}
var res []*HelloWorldEvent
for i, ex := range log.Executions {
for j, e := range ex.Events {
if e.Name != "Hello world!" {
continue
}
event := new(HelloWorldEvent)
err := event.FromStackItem(e.Item)
if err != nil {
return nil, fmt.Errorf("failed to deserialize HelloWorldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
}
res = append(res, event)
}
}
return res, nil
}
// FromStackItem converts provided [stackitem.Array] to HelloWorldEvent or
// returns an error if it's not possible to do to so.
func (e *HelloWorldEvent) FromStackItem(item *stackitem.Array) error {
if item == nil {
return errors.New("nil item")
}
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not an array")
}
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}
var (
index = -1
err error
)
index++
e.Args, err = func(item stackitem.Item) ([]any, error) {
arr, ok := item.Value().([]stackitem.Item)
if !ok {
return nil, errors.New("not an array")
}
res := make([]any, len(arr))
for i := range res {
res[i], err = arr[i].Value(), error(nil)
if err != nil {
return nil, fmt.Errorf("item %d: %w", i, err)
}
}
return res, nil
}(arr[index])
if err != nil {
return fmt.Errorf("field Args: %w", err)
}
return nil
}

View file

@ -27,4 +27,4 @@
"extra": { "extra": {
"Tokens": null "Tokens": null
} }
} }

64
cli/testdata/testwallet_multi.json vendored Normal file
View file

@ -0,0 +1,64 @@
{
"version": "1.0",
"accounts": [
{
"address": "NgHcPxgEKZQV4QBedzyASJrgiANhJqBVLw",
"key": "6PYTbVq2P3AJQwWU5SFMKLjHYco7QABtNRo4ZvLvXhyaYjwMcuZm6xKokT",
"label": "one",
"contract": {
"script": "DCECnmSGVirDOqMr57EHaYz0YMTjaHQtO9FQYu8DMTCDw6VBVuezJw==",
"parameters": [
{
"name": "parameter0",
"type": "Signature"
}
],
"deployed": false
},
"lock": false,
"isDefault": false
},
{
"address": "NLvHRfKAifjio2z9HiwLo9ZnpRPHUbAHgH",
"key": "6PYUjQ8TgR3cduEpG5niUNuPEWi3tYiQsnC4Jha9nGAJ6tAQGUmcrZXsLF",
"label": "two",
"contract": {
"script": "DCECgk91c1ABAX3A1uJNnxhGlp7NwUJScwJzJhrsYrXIbgNBVuezJw==",
"parameters": [
{
"name": "parameter0",
"type": "Signature"
}
],
"deployed": false
},
"lock": false,
"isDefault": false
},
{
"address": "NcDfG8foJx79XSihcDDrx1df7cHAoJBfXj",
"key": "6PYRkUQKWFrTovHyeQZ7X4nWoDXKohtFRKW51LiCz317pwCjmB1cVwpcxz",
"label": "three",
"contract": {
"script": "DCEC9v0ZqBg8f4jJX9WR891M0bazf0FYTNu7MEgpSHrb9CVBVuezJw==",
"parameters": [
{
"name": "parameter0",
"type": "Signature"
}
],
"deployed": false
},
"lock": false,
"isDefault": false
}
],
"scrypt": {
"n": 2,
"r": 1,
"p": 1
},
"extra": {
"Tokens": null
}
}

View file

@ -80,4 +80,4 @@
"extra": { "extra": {
"Tokens": null "Tokens": null
} }
} }

View file

@ -5,13 +5,16 @@ package txctx
import ( import (
"fmt" "fmt"
"io"
"time" "time"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input" "github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/paramcontext" "github.com/nspcc-dev/neo-go/cli/paramcontext"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -37,6 +40,11 @@ var (
Name: "force", Name: "force",
Usage: "Do not ask for a confirmation (and ignore errors)", Usage: "Do not ask for a confirmation (and ignore errors)",
} }
// AwaitFlag is a flag used to wait for the transaction to be included in a block.
AwaitFlag = cli.BoolFlag{
Name: "await",
Usage: "wait for the transaction to be included in a block",
}
) )
// SignAndSend adds network and system fees to the provided transaction and // SignAndSend adds network and system fees to the provided transaction and
@ -48,6 +56,7 @@ func SignAndSend(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *tr
gas = flags.Fixed8FromContext(ctx, "gas") gas = flags.Fixed8FromContext(ctx, "gas")
sysgas = flags.Fixed8FromContext(ctx, "sysgas") sysgas = flags.Fixed8FromContext(ctx, "sysgas")
ver = act.GetVersion() ver = act.GetVersion()
aer *state.AppExecResult
) )
tx.SystemFee += int64(sysgas) tx.SystemFee += int64(sysgas)
@ -66,14 +75,39 @@ func SignAndSend(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *tr
} }
waitTime := time.Since(promptTime) waitTime := time.Since(promptTime)
// Compensate for confirmation waiting. // Compensate for confirmation waiting.
tx.ValidUntilBlock += uint32((waitTime.Milliseconds() / int64(ver.Protocol.MillisecondsPerBlock))) + 1 tx.ValidUntilBlock += uint32(waitTime.Milliseconds()/int64(ver.Protocol.MillisecondsPerBlock)) + 2
}
var (
resTx util.Uint256
vub uint32
)
resTx, vub, err = act.SignAndSend(tx)
if err != nil {
return cli.NewExitError(err, 1)
}
if ctx.Bool("await") {
aer, err = act.Wait(resTx, vub, err)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", resTx.StringLE(), err), 1)
}
} }
_, _, err = act.SignAndSend(tx)
} }
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE()) DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer)
return nil return nil
} }
// DumpTransactionInfo prints transaction info to the given writer.
func DumpTransactionInfo(w io.Writer, h util.Uint256, res *state.AppExecResult) {
fmt.Fprintln(w, h.StringLE())
if res != nil {
fmt.Fprintf(w, "OnChain:\t%t\n", res != nil)
fmt.Fprintf(w, "VMState:\t%s\n", res.VMState.String())
if res.FaultException != "" {
fmt.Fprintf(w, "FaultException:\t%s\n", res.FaultException)
}
}
}

103
cli/util/cancel.go Normal file
View file

@ -0,0 +1,103 @@
package util
import (
"errors"
"fmt"
"strings"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/txctx"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/urfave/cli"
)
func cancelTx(ctx *cli.Context) error {
args := ctx.Args()
if len(args) == 0 {
return cli.NewExitError("transaction hash is missing", 1)
} else if len(args) > 1 {
return cli.NewExitError("only one transaction hash is accepted", 1)
}
txHash, err := util.Uint256DecodeStringLE(strings.TrimPrefix(args[0], "0x"))
if err != nil {
return cli.NewExitError(fmt.Sprintf("invalid tx hash: %s", args[0]), 1)
}
gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel()
acc, w, err := options.GetAccFromContext(ctx)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to get account from context to sign the conflicting transaction: %w", err), 1)
}
defer w.Close()
signers, err := cmdargs.GetSignersAccounts(acc, w, nil, transaction.CalledByEntry)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
}
c, a, exitErr := options.GetRPCWithActor(gctx, ctx, signers)
if exitErr != nil {
return exitErr
}
mainTx, _ := c.GetRawTransactionVerbose(txHash)
if mainTx != nil && !mainTx.Blockhash.Equals(util.Uint256{}) {
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted at block %s", txHash, mainTx.Blockhash.StringLE()), 1)
}
if mainTx != nil && !mainTx.HasSigner(acc.ScriptHash()) {
return cli.NewExitError(fmt.Errorf("account %s is not a signer of the conflicting transaction", acc.Address), 1)
}
resHash, resVub, err := a.SendTunedRun([]byte{byte(opcode.RET)}, []transaction.Attribute{{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: txHash}}}, func(r *result.Invoke, t *transaction.Transaction) error {
err := actor.DefaultCheckerModifier(r, t)
if err != nil {
return err
}
if mainTx != nil && t.NetworkFee < mainTx.NetworkFee+1 {
t.NetworkFee = mainTx.NetworkFee + 1
}
t.NetworkFee += int64(flags.Fixed8FromContext(ctx, "gas"))
if mainTx != nil {
t.ValidUntilBlock = mainTx.ValidUntilBlock
}
return nil
})
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to send conflicting transaction: %w", err), 1)
}
var res *state.AppExecResult
if ctx.Bool("await") {
res, err = a.WaitAny(gctx, resVub, txHash, resHash)
if err != nil {
if errors.Is(err, waiter.ErrTxNotAccepted) {
if mainTx == nil {
return cli.NewExitError(fmt.Errorf("neither target nor conflicting transaction is accepted before the current height %d (ValidUntilBlock value of conlicting transaction). Main transaction is unknown to the provided RPC node, thus still has chances to be accepted, you may try cancellation again", resVub), 1)
}
fmt.Fprintf(ctx.App.Writer, "Neither target nor conflicting transaction is accepted before the current height %d (ValidUntilBlock value of both target and conflicting transactions). Main transaction is not valid anymore, cancellation is successful\n", resVub)
return nil
}
return cli.NewExitError(fmt.Errorf("failed to await target/ conflicting transaction %s/ %s: %w", txHash.StringLE(), resHash.StringLE(), err), 1)
}
if txHash.Equals(res.Container) {
tx, err := c.GetRawTransactionVerbose(txHash)
if err != nil {
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted", txHash), 1)
}
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted at block %s", txHash, tx.Blockhash.StringLE()), 1)
}
fmt.Fprintln(ctx.App.Writer, "Conflicting transaction accepted")
}
txctx.DumpTransactionInfo(ctx.App.Writer, resHash, res)
return nil
}

View file

@ -1,16 +1,32 @@
package util package util
import ( import (
"encoding/base64"
"encoding/hex"
"fmt" "fmt"
"os"
"github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/txctx"
vmcli "github.com/nspcc-dev/neo-go/cli/vm" vmcli "github.com/nspcc-dev/neo-go/cli/vm"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
// NewCommands returns util commands for neo-go CLI. // NewCommands returns util commands for neo-go CLI.
func NewCommands() []cli.Command { func NewCommands() []cli.Command {
txDumpFlags := append([]cli.Flag{}, options.RPC...) txDumpFlags := append([]cli.Flag{}, options.RPC...)
txSendFlags := append(txDumpFlags, txctx.AwaitFlag)
txCancelFlags := append([]cli.Flag{
flags.AddressFlag{
Name: "address, a",
Usage: "address to use as conflicting transaction signee (and gas source)",
},
txctx.GasFlag,
txctx.AwaitFlag,
}, options.RPC...)
txCancelFlags = append(txCancelFlags, options.Wallet...)
return []cli.Command{ return []cli.Command{
{ {
Name: "util", Name: "util",
@ -28,14 +44,35 @@ func NewCommands() []cli.Command {
{ {
Name: "sendtx", Name: "sendtx",
Usage: "Send complete transaction stored in a context file", Usage: "Send complete transaction stored in a context file",
UsageText: "sendtx [-r <endpoint>] <file.in>", UsageText: "sendtx [-r <endpoint>] <file.in> [--await]",
Description: `Sends the transaction from the given context file to the given RPC node if it's Description: `Sends the transaction from the given context file to the given RPC node if it's
completely signed and ready. This command expects a ContractParametersContext completely signed and ready. This command expects a ContractParametersContext
JSON file for input, it can't handle binary (or hex- or base64-encoded) JSON file for input, it can't handle binary (or hex- or base64-encoded)
transactions. transactions. If the --await flag is included, the command waits for the
transaction to be included in a block before exiting.
`, `,
Action: sendTx, Action: sendTx,
Flags: txDumpFlags, Flags: txSendFlags,
},
{
Name: "canceltx",
Usage: "Cancel transaction by sending conflicting transaction",
UsageText: "canceltx <txid> -r <endpoint> --wallet <wallet> [--account <account>] [--wallet-config <path>] [--gas <gas>] [--await]",
Description: `Aims to prevent a transaction from being added to the blockchain by dispatching a more
prioritized conflicting transaction to the specified RPC node. The input for this command should
be the transaction hash. If another account is not specified, the conflicting transaction is
automatically generated and signed by the default account in the wallet. If the target transaction
is in the memory pool of the provided RPC node, the NetworkFee value of the conflicting transaction
is set to the target transaction's NetworkFee value plus one (if it's sufficient for the
conflicting transaction itself), the ValidUntilBlock value of the conflicting transaction is set to the
target transaction's ValidUntilBlock value. If the target transaction is not in the memory pool, standard
NetworkFee calculations are performed based on the calculatenetworkfee RPC request. If the --gas
flag is included, the specified value is added to the resulting conflicting transaction network fee
in both scenarios. When the --await flag is included, the command waits for one of the conflicting
or target transactions to be included in a block.
`,
Action: cancelTx,
Flags: txCancelFlags,
}, },
{ {
Name: "txdump", Name: "txdump",
@ -43,6 +80,28 @@ func NewCommands() []cli.Command {
UsageText: "txdump [-r <endpoint>] <file.in>", UsageText: "txdump [-r <endpoint>] <file.in>",
Action: txDump, Action: txDump,
Flags: txDumpFlags, Flags: txDumpFlags,
Description: `Dumps the transaction from the given parameter context file to
the output. This command expects a ContractParametersContext JSON file for input, it can't handle
binary (or hex- or base64-encoded) transactions. If --rpc-endpoint flag is specified the result
of the given script after running it true the VM will be printed. Otherwise only transaction will
be printed.
`,
},
{
Name: "ops",
Usage: "Pretty-print VM opcodes of the given base64- or hex- encoded script (base64 is checked first). If the input file is specified, then the script is taken from the file.",
UsageText: "ops <base64/hex-encoded script> [-i path-to-file] [--hex]",
Action: handleOps,
Flags: []cli.Flag{
cli.StringFlag{
Name: "in, i",
Usage: "input file containing base64- or hex- encoded script representation",
},
cli.BoolFlag{
Name: "hex",
Usage: "use hex encoding and do not check base64",
},
},
}, },
}, },
}, },
@ -57,3 +116,35 @@ func handleParse(ctx *cli.Context) error {
fmt.Fprint(ctx.App.Writer, res) fmt.Fprint(ctx.App.Writer, res)
return nil return nil
} }
func handleOps(ctx *cli.Context) error {
var (
s string
err error
b []byte
)
in := ctx.String("in")
if len(in) != 0 {
b, err := os.ReadFile(in)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to read file: %w", err), 1)
}
s = string(b)
} else {
if !ctx.Args().Present() {
return cli.NewExitError("missing script", 1)
}
s = ctx.Args()[0]
}
b, err = base64.StdEncoding.DecodeString(s)
if err != nil || ctx.Bool("hex") {
b, err = hex.DecodeString(s)
}
if err != nil {
return cli.NewExitError("unknown encoding: base64 or hex are supported", 1)
}
v := vm.New()
v.LoadScript(b)
v.PrintOps(ctx.App.Writer)
return nil
}

View file

@ -29,7 +29,10 @@ func txDump(ctx *cli.Context) error {
return cli.NewExitError("verifiable item is not a transaction", 1) return cli.NewExitError("verifiable item is not a transaction", 1)
} }
query.DumpApplicationLog(ctx, nil, tx, nil, true) err = query.DumpApplicationLog(ctx, nil, tx, nil, true)
if err != nil {
return cli.NewExitError(err, 1)
}
if ctx.String(options.RPCEndpointFlag) != "" { if ctx.String(options.RPCEndpointFlag) != "" {
gctx, cancel := options.GetTimeoutContext(ctx) gctx, cancel := options.GetTimeoutContext(ctx)

View file

@ -5,6 +5,9 @@ import (
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/paramcontext" "github.com/nspcc-dev/neo-go/cli/paramcontext"
"github.com/nspcc-dev/neo-go/cli/txctx"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -37,6 +40,14 @@ func sendTx(ctx *cli.Context) error {
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1) return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1)
} }
fmt.Fprintln(ctx.App.Writer, res.StringLE()) var aer *state.AppExecResult
if ctx.Bool("await") {
version, err := c.GetVersion()
aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", res.StringLE(), err), 1)
}
}
txctx.DumpTransactionInfo(ctx.App.Writer, res, aer)
return nil return nil
} }

View file

@ -1,10 +1,19 @@
package util_test package util_test
import ( import (
"fmt"
"os"
"path/filepath"
"strings"
"testing" "testing"
"time"
"github.com/nspcc-dev/neo-go/internal/testcli" "github.com/nspcc-dev/neo-go/internal/testcli"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/stretchr/testify/require"
) )
func TestUtilConvert(t *testing.T) { func TestUtilConvert(t *testing.T) {
@ -24,3 +33,160 @@ func TestUtilConvert(t *testing.T) {
e.CheckNextLine(t, "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAzMDIwMQ==") // string to base64 e.CheckNextLine(t, "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAzMDIwMQ==") // string to base64
e.CheckEOF(t) e.CheckEOF(t)
} }
func TestUtilOps(t *testing.T) {
e := testcli.NewExecutor(t, false)
base64Str := "EUA="
hexStr := "1140"
check := func(t *testing.T) {
e.CheckNextLine(t, "INDEX.*OPCODE.*PARAMETER")
e.CheckNextLine(t, "PUSH1")
e.CheckNextLine(t, "RET")
e.CheckEOF(t)
}
e.Run(t, "neo-go", "util", "ops", base64Str) // base64
check(t)
e.Run(t, "neo-go", "util", "ops", hexStr) // base64 is checked firstly by default, but it's invalid script if decoded from base64
e.CheckNextLine(t, "INDEX.*OPCODE.*PARAMETER")
e.CheckNextLine(t, ".*ERROR: incorrect opcode")
e.CheckEOF(t)
e.Run(t, "neo-go", "util", "ops", "--hex", hexStr) // explicitly specify hex encoding
check(t)
e.RunWithError(t, "neo-go", "util", "ops", "%&~*") // unknown encoding
tmp := filepath.Join(t.TempDir(), "script_base64.txt")
require.NoError(t, os.WriteFile(tmp, []byte(base64Str), os.ModePerm))
e.Run(t, "neo-go", "util", "ops", "--in", tmp) // base64 from file
check(t)
tmp = filepath.Join(t.TempDir(), "script_hex.txt")
require.NoError(t, os.WriteFile(tmp, []byte(hexStr), os.ModePerm))
e.Run(t, "neo-go", "util", "ops", "--hex", "--in", tmp) // hex from file
check(t)
}
func TestUtilCancelTx(t *testing.T) {
e := testcli.NewExecutorSuspended(t)
w, err := wallet.NewWalletFromFile("../testdata/testwallet.json")
require.NoError(t, err)
transferArgs := []string{
"neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--to", w.Accounts[0].Address,
"--token", "NEO",
"--from", testcli.ValidatorAddr,
"--force",
}
args := []string{"neo-go", "util", "canceltx",
"-r", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", testcli.ValidatorAddr}
e.In.WriteString("one\r")
e.Run(t, append(transferArgs, "--amount", "1")...)
line := e.GetNextLine(t)
txHash, err := util.Uint256DecodeStringLE(line)
require.NoError(t, err)
_, ok := e.Chain.GetMemPool().TryGetValue(txHash)
require.True(t, ok)
t.Run("invalid", func(t *testing.T) {
t.Run("missing tx argument", func(t *testing.T) {
e.RunWithError(t, args...)
})
t.Run("excessive arguments", func(t *testing.T) {
e.RunWithError(t, append(args, txHash.StringLE(), txHash.StringLE())...)
})
t.Run("invalid hash", func(t *testing.T) {
e.RunWithError(t, append(args, "notahash")...)
})
t.Run("not signed by main signer", func(t *testing.T) {
e.In.WriteString("one\r")
e.RunWithError(t, "neo-go", "util", "canceltx",
"-r", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", testcli.MultisigAddr, txHash.StringLE())
})
t.Run("wrong rpc endpoint", func(t *testing.T) {
e.In.WriteString("one\r")
e.RunWithError(t, "neo-go", "util", "canceltx",
"-r", "http://localhost:20331",
"--wallet", testcli.ValidatorWallet, txHash.StringLE())
})
})
e.In.WriteString("one\r")
e.Run(t, append(args, txHash.StringLE())...)
resHash, err := util.Uint256DecodeStringLE(e.GetNextLine(t))
require.NoError(t, err)
_, _, err = e.Chain.GetTransaction(resHash)
require.NoError(t, err)
e.CheckEOF(t)
go e.Chain.Run()
require.Eventually(t, func() bool {
_, aerErr := e.Chain.GetAppExecResults(resHash, trigger.Application)
return aerErr == nil
}, time.Second*2, time.Millisecond*50)
}
func TestAwaitUtilCancelTx(t *testing.T) {
e := testcli.NewExecutor(t, true)
w, err := wallet.NewWalletFromFile("../testdata/testwallet.json")
require.NoError(t, err)
transferArgs := []string{
"neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--to", w.Accounts[0].Address,
"--token", "NEO",
"--from", testcli.ValidatorAddr,
"--force",
}
args := []string{"neo-go", "util", "canceltx",
"-r", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", testcli.ValidatorAddr,
"--await"}
e.In.WriteString("one\r")
e.Run(t, append(transferArgs, "--amount", "1")...)
line := e.GetNextLine(t)
txHash, err := util.Uint256DecodeStringLE(line)
require.NoError(t, err)
_, ok := e.Chain.GetMemPool().TryGetValue(txHash)
require.True(t, ok)
// Allow both cases: either target or conflicting tx acceptance.
e.In.WriteString("one\r")
err = e.RunUnchecked(t, append(args, txHash.StringLE())...)
switch {
case err == nil:
response := e.GetNextLine(t)
require.Equal(t, "Conflicting transaction accepted", response)
resHash, _ := e.CheckAwaitableTxPersisted(t)
require.NotEqual(t, resHash, txHash)
case strings.Contains(err.Error(), fmt.Sprintf("target transaction %s is accepted", txHash)) ||
strings.Contains(err.Error(), fmt.Sprintf("failed to send conflicting transaction: Invalid transaction attribute (-507) - invalid attribute: conflicting transaction %s is already on chain", txHash)):
tx, _ := e.GetTransaction(t, txHash)
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
require.NoError(t, err)
require.Equal(t, 1, len(aer))
require.Equal(t, vmstate.Halt, aer[0].VMState)
default:
t.Fatal(fmt.Errorf("unexpected error: %w", err))
}
}

View file

@ -28,12 +28,14 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig" "github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
@ -51,7 +53,7 @@ const (
chainKey = "chain" chainKey = "chain"
chainCfgKey = "chainCfg" chainCfgKey = "chainCfg"
icKey = "ic" icKey = "ic"
manifestKey = "manifest" contractStateKey = "contractState"
exitFuncKey = "exitFunc" exitFuncKey = "exitFunc"
readlineInstanceKey = "readlineKey" readlineInstanceKey = "readlineKey"
printLogoKey = "printLogoKey" printLogoKey = "printLogoKey"
@ -64,6 +66,7 @@ const (
gasFlagFullName = "gas" gasFlagFullName = "gas"
backwardsFlagFullName = "backwards" backwardsFlagFullName = "backwards"
diffFlagFullName = "diff" diffFlagFullName = "diff"
hashFlagFullName = "hash"
) )
var ( var (
@ -76,6 +79,10 @@ var (
Name: gasFlagFullName, Name: gasFlagFullName,
Usage: "GAS limit for this execution (integer number, satoshi).", Usage: "GAS limit for this execution (integer number, satoshi).",
} }
hashFlag = cli.StringFlag{
Name: hashFlagFullName,
Usage: "Smart-contract hash in LE form or address",
}
) )
var commands = []cli.Command{ var commands = []cli.Command{
@ -150,10 +157,12 @@ Example:
}, },
{ {
Name: "loadnef", Name: "loadnef",
Usage: "Load a NEF-consistent script into the VM optionally attaching to it provided signers with scopes", Usage: "Load a NEF (possibly with a contract hash) into the VM optionally using provided scoped signers in the context",
UsageText: `loadnef [--historic <height>] [--gas <int>] <file> <manifest> [<signer-with-scope>, ...]`, UsageText: `loadnef [--historic <height>] [--gas <int>] [--hash <hash-or-address>] <file> [<manifest>] [-- <signer-with-scope>, ...]`,
Flags: []cli.Flag{historicFlag, gasFlag}, Flags: []cli.Flag{historicFlag, gasFlag, hashFlag},
Description: `<file> and <manifest> parameters are mandatory. Description: `<file> parameter is mandatory, <manifest> parameter (if omitted) will
be guessed from the <file> parameter by replacing '.nef' suffix with '.manifest.json'
suffix.
` + cmdargs.SignersParsingDoc + ` ` + cmdargs.SignersParsingDoc + `
@ -164,7 +173,7 @@ Example:
{ {
Name: "loadbase64", Name: "loadbase64",
Usage: "Load a base64-encoded script string into the VM optionally attaching to it provided signers with scopes", Usage: "Load a base64-encoded script string into the VM optionally attaching to it provided signers with scopes",
UsageText: `loadbase64 [--historic <height>] [--gas <int>] <string> [<signer-with-scope>, ...]`, UsageText: `loadbase64 [--historic <height>] [--gas <int>] <string> [-- <signer-with-scope>, ...]`,
Flags: []cli.Flag{historicFlag, gasFlag}, Flags: []cli.Flag{historicFlag, gasFlag},
Description: `<string> is mandatory parameter. Description: `<string> is mandatory parameter.
@ -177,7 +186,7 @@ Example:
{ {
Name: "loadhex", Name: "loadhex",
Usage: "Load a hex-encoded script string into the VM optionally attaching to it provided signers with scopes", Usage: "Load a hex-encoded script string into the VM optionally attaching to it provided signers with scopes",
UsageText: `loadhex [--historic <height>] [--gas <int>] <string> [<signer-with-scope>, ...]`, UsageText: `loadhex [--historic <height>] [--gas <int>] <string> [-- <signer-with-scope>, ...]`,
Flags: []cli.Flag{historicFlag, gasFlag}, Flags: []cli.Flag{historicFlag, gasFlag},
Description: `<string> is mandatory parameter. Description: `<string> is mandatory parameter.
@ -189,9 +198,9 @@ Example:
}, },
{ {
Name: "loadgo", Name: "loadgo",
Usage: "Compile and load a Go file with the manifest into the VM optionally attaching to it provided signers with scopes", Usage: "Compile and load a Go file with the manifest into the VM optionally attaching to it provided signers with scopes and setting provided hash",
UsageText: `loadgo [--historic <height>] [--gas <int>] <file> [<signer-with-scope>, ...]`, UsageText: `loadgo [--historic <height>] [--gas <int>] [--hash <hash-or-address>] <file> [-- <signer-with-scope>, ...]`,
Flags: []cli.Flag{historicFlag, gasFlag}, Flags: []cli.Flag{historicFlag, gasFlag, hashFlag},
Description: `<file> is mandatory parameter. Description: `<file> is mandatory parameter.
` + cmdargs.SignersParsingDoc + ` ` + cmdargs.SignersParsingDoc + `
@ -220,7 +229,7 @@ Example:
{ {
Name: "loaddeployed", Name: "loaddeployed",
Usage: "Load deployed contract into the VM from chain optionally attaching to it provided signers with scopes", Usage: "Load deployed contract into the VM from chain optionally attaching to it provided signers with scopes",
UsageText: `loaddeployed [--historic <height>] [--gas <int>] <hash-or-address-or-id> [<signer-with-scope>, ...]`, UsageText: `loaddeployed [--historic <height>] [--gas <int>] <hash-or-address-or-id> [-- <signer-with-scope>, ...]`,
Flags: []cli.Flag{historicFlag, gasFlag}, Flags: []cli.Flag{historicFlag, gasFlag},
Description: `Load deployed contract into the VM from chain optionally attaching to it provided signers with scopes. Description: `Load deployed contract into the VM from chain optionally attaching to it provided signers with scopes.
If '--historic' flag specified, then the historic contract state (historic script and manifest) will be loaded. If '--historic' flag specified, then the historic contract state (historic script and manifest) will be loaded.
@ -487,7 +496,7 @@ func NewWithConfig(printLogotype bool, onExit func(int), c *readline.Config, cfg
chainKey: chain, chainKey: chain,
chainCfgKey: cfg, chainCfgKey: cfg,
icKey: ic, icKey: ic,
manifestKey: new(manifest.Manifest), contractStateKey: new(state.ContractBase),
exitFuncKey: exitF, exitFuncKey: exitF,
readlineInstanceKey: l, readlineInstanceKey: l,
printLogoKey: printLogotype, printLogoKey: printLogotype,
@ -520,8 +529,8 @@ func getInteropContextFromContext(app *cli.App) *interop.Context {
return app.Metadata[icKey].(*interop.Context) return app.Metadata[icKey].(*interop.Context)
} }
func getManifestFromContext(app *cli.App) *manifest.Manifest { func getContractStateFromContext(app *cli.App) *state.ContractBase {
return app.Metadata[manifestKey].(*manifest.Manifest) return app.Metadata[contractStateKey].(*state.ContractBase)
} }
func getPrintLogoFromContext(app *cli.App) bool { func getPrintLogoFromContext(app *cli.App) bool {
@ -532,8 +541,8 @@ func setInteropContextInContext(app *cli.App, ic *interop.Context) {
app.Metadata[icKey] = ic app.Metadata[icKey] = ic
} }
func setManifestInContext(app *cli.App, m *manifest.Manifest) { func setContractStateInContext(app *cli.App, cs *state.ContractBase) {
app.Metadata[manifestKey] = m app.Metadata[contractStateKey] = cs
} }
func checkVMIsReady(app *cli.App) bool { func checkVMIsReady(app *cli.App) bool {
@ -607,7 +616,7 @@ func getInstructionParameter(c *cli.Context) (int, error) {
} }
n, err := strconv.Atoi(args[0]) n, err := strconv.Atoi(args[0])
if err != nil { if err != nil {
return 0, fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors return 0, fmt.Errorf("%w: %w", ErrInvalidParameter, err)
} }
return n, nil return n, nil
} }
@ -669,12 +678,49 @@ func prepareVM(c *cli.Context, tx *transaction.Transaction) error {
return nil return nil
} }
func getHashFlag(c *cli.Context) (util.Uint160, error) {
if !c.IsSet(hashFlagFullName) {
return util.Uint160{}, nil
}
h, err := flags.ParseAddress(c.String(hashFlagFullName))
if err != nil {
return util.Uint160{}, fmt.Errorf("failed to parse contract hash: %w", err)
}
return h, nil
}
func handleLoadNEF(c *cli.Context) error { func handleLoadNEF(c *cli.Context) error {
args := c.Args() args := c.Args()
if len(args) < 2 { if len(args) < 1 {
return fmt.Errorf("%w: <file> <manifest>", ErrMissingParameter) return fmt.Errorf("%w: <nef> is required", ErrMissingParameter)
} }
b, err := os.ReadFile(args[0]) nefFile := args[0]
var (
manifestFile string
signersStartOffset int
)
if len(args) == 2 {
manifestFile = args[1]
} else if len(args) == 3 {
if args[1] != cmdargs.CosignersSeparator {
return fmt.Errorf("%w: `%s` was expected as the second parameter, got %s", ErrInvalidParameter, cmdargs.CosignersSeparator, args[1])
}
signersStartOffset = 2
} else if len(args) > 3 {
if args[1] == cmdargs.CosignersSeparator {
signersStartOffset = 2
} else {
manifestFile = args[1]
if args[2] != cmdargs.CosignersSeparator {
return fmt.Errorf("%w: `%s` was expected as the third parameter, got %s", ErrInvalidParameter, cmdargs.CosignersSeparator, args[2])
}
signersStartOffset = 3
}
}
if len(manifestFile) == 0 {
manifestFile = strings.TrimSuffix(nefFile, ".nef") + ".manifest.json"
}
b, err := os.ReadFile(nefFile)
if err != nil { if err != nil {
return err return err
} }
@ -682,24 +728,34 @@ func handleLoadNEF(c *cli.Context) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to decode NEF file: %w", err) return fmt.Errorf("failed to decode NEF file: %w", err)
} }
m, err := getManifestFromFile(args[1]) m, err := getManifestFromFile(manifestFile)
if err != nil { if err != nil {
return fmt.Errorf("failed to read manifest: %w", err) return fmt.Errorf("failed to read manifest: %w", err)
} }
var signers []transaction.Signer var signers []transaction.Signer
if len(args) > 2 { if signersStartOffset != 0 && len(args) > signersStartOffset {
signers, err = cmdargs.ParseSigners(c.Args()[2:]) signers, err = cmdargs.ParseSigners(c.Args()[signersStartOffset:])
if err != nil { if err != nil {
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors return fmt.Errorf("%w: failed to parse signers: %w", ErrInvalidParameter, err)
} }
} }
err = prepareVM(c, createFakeTransaction(nef.Script, signers)) err = prepareVM(c, createFakeTransaction(nef.Script, signers))
if err != nil { if err != nil {
return err return err
} }
h, err := getHashFlag(c)
if err != nil {
return err
}
cs := &state.ContractBase{
Hash: h,
NEF: nef,
Manifest: *m,
}
setContractStateInContext(c.App, cs)
v := getVMFromContext(c.App) v := getVMFromContext(c.App)
fmt.Fprintf(c.App.Writer, "READY: loaded %d instructions\n", v.Context().LenInstr()) fmt.Fprintf(c.App.Writer, "READY: loaded %d instructions\n", v.Context().LenInstr())
setManifestInContext(c.App, m)
changePrompt(c.App) changePrompt(c.App)
return nil return nil
} }
@ -711,13 +767,19 @@ func handleLoadBase64(c *cli.Context) error {
} }
b, err := base64.StdEncoding.DecodeString(args[0]) b, err := base64.StdEncoding.DecodeString(args[0])
if err != nil { if err != nil {
return fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
} }
var signers []transaction.Signer var signers []transaction.Signer
if len(args) > 1 { if len(args) > 1 {
signers, err = cmdargs.ParseSigners(args[1:]) if args[1] != cmdargs.CosignersSeparator {
return fmt.Errorf("%w: `%s` was expected as the second parameter, got %s", ErrInvalidParameter, cmdargs.CosignersSeparator, args[1])
}
if len(args) < 3 {
return fmt.Errorf("%w: signers expected after `%s`, got none", ErrInvalidParameter, cmdargs.CosignersSeparator)
}
signers, err = cmdargs.ParseSigners(args[2:])
if err != nil { if err != nil {
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
} }
} }
err = prepareVM(c, createFakeTransaction(b, signers)) err = prepareVM(c, createFakeTransaction(b, signers))
@ -745,13 +807,19 @@ func handleLoadHex(c *cli.Context) error {
} }
b, err := hex.DecodeString(args[0]) b, err := hex.DecodeString(args[0])
if err != nil { if err != nil {
return fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
} }
var signers []transaction.Signer var signers []transaction.Signer
if len(args) > 1 { if len(args) > 1 {
signers, err = cmdargs.ParseSigners(args[1:]) if args[1] != cmdargs.CosignersSeparator {
return fmt.Errorf("%w: `%s` was expected as the second parameter, got %s", ErrInvalidParameter, cmdargs.CosignersSeparator, args[1])
}
if len(args) < 3 {
return fmt.Errorf("%w: signers expected after `%s`, got none", ErrInvalidParameter, cmdargs.CosignersSeparator)
}
signers, err = cmdargs.ParseSigners(args[2:])
if err != nil { if err != nil {
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
} }
} }
err = prepareVM(c, createFakeTransaction(b, signers)) err = prepareVM(c, createFakeTransaction(b, signers))
@ -771,7 +839,7 @@ func handleLoadGo(c *cli.Context) error {
} }
name := strings.TrimSuffix(args[0], ".go") name := strings.TrimSuffix(args[0], ".go")
b, di, err := compiler.CompileWithOptions(args[0], nil, &compiler.Options{Name: name}) ne, di, err := compiler.CompileWithOptions(args[0], nil, &compiler.Options{Name: name})
if err != nil { if err != nil {
return fmt.Errorf("failed to compile: %w", err) return fmt.Errorf("failed to compile: %w", err)
} }
@ -783,18 +851,34 @@ func handleLoadGo(c *cli.Context) error {
} }
var signers []transaction.Signer var signers []transaction.Signer
if len(args) > 1 { if len(args) > 1 {
signers, err = cmdargs.ParseSigners(args[1:]) if args[1] != cmdargs.CosignersSeparator {
return fmt.Errorf("%w: `%s` was expected as the second parameter, got %s", ErrInvalidParameter, cmdargs.CosignersSeparator, args[1])
}
if len(args) < 3 {
return fmt.Errorf("%w: signers expected after `%s`, got none", ErrInvalidParameter, cmdargs.CosignersSeparator)
}
signers, err = cmdargs.ParseSigners(args[2:])
if err != nil { if err != nil {
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
} }
} }
err = prepareVM(c, createFakeTransaction(b.Script, signers)) err = prepareVM(c, createFakeTransaction(ne.Script, signers))
if err != nil { if err != nil {
return err return err
} }
h, err := getHashFlag(c)
if err != nil {
return err
}
cs := &state.ContractBase{
Hash: h,
NEF: *ne,
Manifest: *m,
}
setContractStateInContext(c.App, cs)
v := getVMFromContext(c.App) v := getVMFromContext(c.App)
setManifestInContext(c.App, m)
fmt.Fprintf(c.App.Writer, "READY: loaded %d instructions\n", v.Context().LenInstr()) fmt.Fprintf(c.App.Writer, "READY: loaded %d instructions\n", v.Context().LenInstr())
changePrompt(c.App) changePrompt(c.App)
return nil return nil
@ -849,7 +933,8 @@ func handleLoadDeployed(c *cli.Context) error {
if !c.Args().Present() { if !c.Args().Present() {
return errors.New("contract hash, address or ID is mandatory argument") return errors.New("contract hash, address or ID is mandatory argument")
} }
hashOrID := c.Args().Get(0) args := c.Args()
hashOrID := args[0]
ic := getInteropContextFromContext(c.App) ic := getInteropContextFromContext(c.App)
h, err := flags.ParseAddress(hashOrID) h, err := flags.ParseAddress(hashOrID)
if err != nil { if err != nil {
@ -868,10 +953,16 @@ func handleLoadDeployed(c *cli.Context) error {
} }
var signers []transaction.Signer var signers []transaction.Signer
if len(c.Args()) > 1 { if len(args) > 1 {
signers, err = cmdargs.ParseSigners(c.Args()[1:]) if args[1] != cmdargs.CosignersSeparator {
return fmt.Errorf("%w: %s was expected as the second parameter, got %s", ErrInvalidParameter, cmdargs.CosignersSeparator, args[1])
}
if len(args) < 3 {
return fmt.Errorf("%w: signers expected after `%s`, got none", ErrInvalidParameter, cmdargs.CosignersSeparator)
}
signers, err = cmdargs.ParseSigners(args[2:])
if err != nil { if err != nil {
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
} }
} }
err = prepareVM(c, createFakeTransaction(cs.NEF.Script, signers)) // prepare VM one more time for proper IC initialization. err = prepareVM(c, createFakeTransaction(cs.NEF.Script, signers)) // prepare VM one more time for proper IC initialization.
@ -884,7 +975,7 @@ func handleLoadDeployed(c *cli.Context) error {
ic.VM.GasLimit = gasLimit ic.VM.GasLimit = gasLimit
ic.VM.LoadScriptWithHash(cs.NEF.Script, cs.Hash, callflag.All) ic.VM.LoadScriptWithHash(cs.NEF.Script, cs.Hash, callflag.All)
fmt.Fprintf(c.App.Writer, "READY: loaded %d instructions\n", ic.VM.Context().LenInstr()) fmt.Fprintf(c.App.Writer, "READY: loaded %d instructions\n", ic.VM.Context().LenInstr())
setManifestInContext(c.App, &cs.Manifest) setContractStateInContext(c.App, &cs.ContractBase)
changePrompt(c.App) changePrompt(c.App)
return nil return nil
} }
@ -939,9 +1030,9 @@ func resetInteropContext(app *cli.App, tx *transaction.Transaction, height ...ui
return nil return nil
} }
// resetManifest removes manifest from app context. // resetContractState removes loaded contract state from app context.
func resetManifest(app *cli.App) { func resetContractState(app *cli.App) {
setManifestInContext(app, nil) setContractStateInContext(app, nil)
} }
// resetState resets state of the app (clear interop context and manifest) so that it's ready // resetState resets state of the app (clear interop context and manifest) so that it's ready
@ -951,7 +1042,7 @@ func resetState(app *cli.App, tx *transaction.Transaction, height ...uint32) err
if err != nil { if err != nil {
return err return err
} }
resetManifest(app) resetContractState(app)
return nil return nil
} }
@ -970,7 +1061,7 @@ func getManifestFromFile(name string) (*manifest.Manifest, error) {
func handleRun(c *cli.Context) error { func handleRun(c *cli.Context) error {
v := getVMFromContext(c.App) v := getVMFromContext(c.App)
m := getManifestFromContext(c.App) cs := getContractStateFromContext(c.App)
args := c.Args() args := c.Args()
if len(args) != 0 { if len(args) != 0 {
var ( var (
@ -978,11 +1069,12 @@ func handleRun(c *cli.Context) error {
offset int offset int
err error err error
runCurrent = args[0] != "_" runCurrent = args[0] != "_"
hasRet bool
) )
_, scParams, err := cmdargs.ParseParams(args[1:], true) _, scParams, err := cmdargs.ParseParams(args[1:], true)
if err != nil { if err != nil {
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
} }
params = make([]stackitem.Item, len(scParams)) params = make([]stackitem.Item, len(scParams))
for i := range scParams { for i := range scParams {
@ -992,27 +1084,35 @@ func handleRun(c *cli.Context) error {
} }
} }
if runCurrent { if runCurrent {
if m == nil { if cs == nil {
return fmt.Errorf("manifest is not loaded; either use 'run' command to run loaded script from the start or use 'loadgo' and 'loadnef' commands to provide manifest") return fmt.Errorf("manifest is not loaded; either use 'run' command to run loaded script from the start or use 'loadgo', 'loadnef' or 'loaddeployed' commands to provide manifest")
} }
md := m.ABI.GetMethod(args[0], len(params)) md := cs.Manifest.ABI.GetMethod(args[0], len(params))
if md == nil { if md == nil {
return fmt.Errorf("%w: method not found", ErrInvalidParameter) return fmt.Errorf("%w: method not found", ErrInvalidParameter)
} }
hasRet = md.ReturnType != smartcontract.VoidType
offset = md.Offset offset = md.Offset
var initOff = -1
if initMD := cs.Manifest.ABI.GetMethod(manifest.MethodInit, 0); initMD != nil {
initOff = initMD.Offset
}
// Clear context loaded by 'loadgo', 'loadnef' or 'loaddeployed' to properly handle LoadNEFMethod.
// At the same time, preserve previously set gas limit and the set of breakpoints.
ic := getInteropContextFromContext(c.App)
gasLimit := v.GasLimit
breaks := v.Context().BreakPoints() // We ensure that there's a context loaded.
ic.ReuseVM(v)
v.GasLimit = gasLimit
v.LoadNEFMethod(&cs.NEF, &cs.Manifest, util.Uint160{}, cs.Hash, callflag.All, hasRet, offset, initOff, nil)
for _, bp := range breaks {
v.AddBreakPoint(bp)
}
} }
for i := len(params) - 1; i >= 0; i-- { for i := len(params) - 1; i >= 0; i-- {
v.Estack().PushVal(params[i]) v.Estack().PushVal(params[i])
} }
if runCurrent {
if !v.Ready() {
return errors.New("no program loaded")
}
v.Context().Jump(offset)
if initMD := m.ABI.GetMethod(manifest.MethodInit, 0); initMD != nil {
v.Call(initMD.Offset)
}
}
} }
runVMWithHandling(c) runVMWithHandling(c)
changePrompt(c.App) changePrompt(c.App)
@ -1085,7 +1185,7 @@ func handleStep(c *cli.Context) error {
if len(args) > 0 { if len(args) > 0 {
n, err = strconv.Atoi(args[0]) n, err = strconv.Atoi(args[0])
if err != nil { if err != nil {
return fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
} }
} }
v.AddBreakPointRel(n) v.AddBreakPointRel(n)
@ -1336,58 +1436,57 @@ func Parse(args []string) (string, error) {
return "", ErrMissingParameter return "", ErrMissingParameter
} }
arg := args[0] arg := args[0]
buf := bytes.NewBuffer(nil) var buf []byte
if val, err := strconv.ParseInt(arg, 10, 64); err == nil { if val, err := strconv.ParseInt(arg, 10, 64); err == nil {
bs := bigint.ToBytes(big.NewInt(val)) bs := bigint.ToBytes(big.NewInt(val))
buf.WriteString(fmt.Sprintf("Integer to Hex\t%s\n", hex.EncodeToString(bs))) buf = fmt.Appendf(buf, "Integer to Hex\t%s\n", hex.EncodeToString(bs))
buf.WriteString(fmt.Sprintf("Integer to Base64\t%s\n", base64.StdEncoding.EncodeToString(bs))) buf = fmt.Appendf(buf, "Integer to Base64\t%s\n", base64.StdEncoding.EncodeToString(bs))
} }
noX := strings.TrimPrefix(arg, "0x") noX := strings.TrimPrefix(arg, "0x")
if rawStr, err := hex.DecodeString(noX); err == nil { if rawStr, err := hex.DecodeString(noX); err == nil {
if val, err := util.Uint160DecodeBytesBE(rawStr); err == nil { if val, err := util.Uint160DecodeBytesBE(rawStr); err == nil {
buf.WriteString(fmt.Sprintf("BE ScriptHash to Address\t%s\n", address.Uint160ToString(val))) buf = fmt.Appendf(buf, "BE ScriptHash to Address\t%s\n", address.Uint160ToString(val))
buf.WriteString(fmt.Sprintf("LE ScriptHash to Address\t%s\n", address.Uint160ToString(val.Reverse()))) buf = fmt.Appendf(buf, "LE ScriptHash to Address\t%s\n", address.Uint160ToString(val.Reverse()))
} }
if pub, err := keys.NewPublicKeyFromBytes(rawStr, elliptic.P256()); err == nil { if pub, err := keys.NewPublicKeyFromBytes(rawStr, elliptic.P256()); err == nil {
sh := pub.GetScriptHash() sh := pub.GetScriptHash()
buf.WriteString(fmt.Sprintf("Public key to BE ScriptHash\t%s\n", sh)) buf = fmt.Appendf(buf, "Public key to BE ScriptHash\t%s\n", sh)
buf.WriteString(fmt.Sprintf("Public key to LE ScriptHash\t%s\n", sh.Reverse())) buf = fmt.Appendf(buf, "Public key to LE ScriptHash\t%s\n", sh.Reverse())
buf.WriteString(fmt.Sprintf("Public key to Address\t%s\n", address.Uint160ToString(sh))) buf = fmt.Appendf(buf, "Public key to Address\t%s\n", address.Uint160ToString(sh))
} }
buf.WriteString(fmt.Sprintf("Hex to String\t%s\n", fmt.Sprintf("%q", string(rawStr)))) buf = fmt.Appendf(buf, "Hex to String\t%s\n", fmt.Sprintf("%q", string(rawStr)))
buf.WriteString(fmt.Sprintf("Hex to Integer\t%s\n", bigint.FromBytes(rawStr))) buf = fmt.Appendf(buf, "Hex to Integer\t%s\n", bigint.FromBytes(rawStr))
buf.WriteString(fmt.Sprintf("Swap Endianness\t%s\n", hex.EncodeToString(slice.CopyReverse(rawStr)))) buf = fmt.Appendf(buf, "Swap Endianness\t%s\n", hex.EncodeToString(slice.CopyReverse(rawStr)))
} }
if addr, err := address.StringToUint160(arg); err == nil { if addr, err := address.StringToUint160(arg); err == nil {
buf.WriteString(fmt.Sprintf("Address to BE ScriptHash\t%s\n", addr)) buf = fmt.Appendf(buf, "Address to BE ScriptHash\t%s\n", addr)
buf.WriteString(fmt.Sprintf("Address to LE ScriptHash\t%s\n", addr.Reverse())) buf = fmt.Appendf(buf, "Address to LE ScriptHash\t%s\n", addr.Reverse())
buf.WriteString(fmt.Sprintf("Address to Base64 (BE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesBE()))) buf = fmt.Appendf(buf, "Address to Base64 (BE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesBE()))
buf.WriteString(fmt.Sprintf("Address to Base64 (LE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesLE()))) buf = fmt.Appendf(buf, "Address to Base64 (LE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesLE()))
} }
if rawStr, err := base64.StdEncoding.DecodeString(arg); err == nil { if rawStr, err := base64.StdEncoding.DecodeString(arg); err == nil {
buf.WriteString(fmt.Sprintf("Base64 to String\t%s\n", fmt.Sprintf("%q", string(rawStr)))) buf = fmt.Appendf(buf, "Base64 to String\t%s\n", fmt.Sprintf("%q", string(rawStr)))
buf.WriteString(fmt.Sprintf("Base64 to BigInteger\t%s\n", bigint.FromBytes(rawStr))) buf = fmt.Appendf(buf, "Base64 to BigInteger\t%s\n", bigint.FromBytes(rawStr))
if u, err := util.Uint160DecodeBytesBE(rawStr); err == nil { if u, err := util.Uint160DecodeBytesBE(rawStr); err == nil {
buf.WriteString(fmt.Sprintf("Base64 to BE ScriptHash\t%s\n", u.StringBE())) buf = fmt.Appendf(buf, "Base64 to BE ScriptHash\t%s\n", u.StringBE())
buf.WriteString(fmt.Sprintf("Base64 to LE ScriptHash\t%s\n", u.StringLE())) buf = fmt.Appendf(buf, "Base64 to LE ScriptHash\t%s\n", u.StringLE())
buf.WriteString(fmt.Sprintf("Base64 to Address (BE)\t%s\n", address.Uint160ToString(u))) buf = fmt.Appendf(buf, "Base64 to Address (BE)\t%s\n", address.Uint160ToString(u))
buf.WriteString(fmt.Sprintf("Base64 to Address (LE)\t%s\n", address.Uint160ToString(u.Reverse()))) buf = fmt.Appendf(buf, "Base64 to Address (LE)\t%s\n", address.Uint160ToString(u.Reverse()))
} }
} }
buf.WriteString(fmt.Sprintf("String to Hex\t%s\n", hex.EncodeToString([]byte(arg)))) buf = fmt.Appendf(buf, "String to Hex\t%s\n", hex.EncodeToString([]byte(arg)))
buf.WriteString(fmt.Sprintf("String to Base64\t%s\n", base64.StdEncoding.EncodeToString([]byte(arg)))) buf = fmt.Appendf(buf, "String to Base64\t%s\n", base64.StdEncoding.EncodeToString([]byte(arg)))
out := buf.Bytes() res := bytes.NewBuffer(nil)
buf = bytes.NewBuffer(nil) w := tabwriter.NewWriter(res, 0, 4, 4, '\t', 0)
w := tabwriter.NewWriter(buf, 0, 4, 4, '\t', 0) if _, err := w.Write(buf); err != nil {
if _, err := w.Write(out); err != nil {
return "", err return "", err
} }
if err := w.Flush(); err != nil { if err := w.Flush(); err != nil {
return "", err return "", err
} }
return buf.String(), nil return res.String(), nil
} }
const logo = ` const logo = `

View file

@ -14,13 +14,16 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"testing" "testing"
"time" "time"
"github.com/chzyer/readline" "github.com/chzyer/readline"
"github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/paramcontext" "github.com/nspcc-dev/neo-go/cli/paramcontext"
"github.com/nspcc-dev/neo-go/internal/basicchain" "github.com/nspcc-dev/neo-go/internal/basicchain"
"github.com/nspcc-dev/neo-go/internal/random" "github.com/nspcc-dev/neo-go/internal/random"
"github.com/nspcc-dev/neo-go/internal/versionutil"
"github.com/nspcc-dev/neo-go/pkg/compiler" "github.com/nspcc-dev/neo-go/pkg/compiler"
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
@ -40,9 +43,11 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/atomic"
) )
// Keep contract NEFs consistent between runs.
const _ = versionutil.TestVersion
type readCloser struct { type readCloser struct {
sync.Mutex sync.Mutex
bytes.Buffer bytes.Buffer
@ -88,10 +93,11 @@ func newTestVMCLIWithLogoAndCustomConfig(t *testing.T, printLogo bool, cfg *conf
} }
var c config.Config var c config.Config
if cfg == nil { if cfg == nil {
configPath := "../../config/protocol.unit_testnet.single.yml" configPath := filepath.Join("..", "..", "config", "protocol.unit_testnet.single.yml")
var err error var err error
c, err = config.LoadFile(configPath) c, err = config.LoadFile(configPath, filepath.Join("..", "..", "config"))
require.NoError(t, err, "could not load chain config") require.NoError(t, err, "could not load chain config")
require.Equal(t, filepath.Join("..", "..", "testdata", "wallet1_solo.json"), c.ApplicationConfiguration.Consensus.UnlockWallet.Path)
c.ApplicationConfiguration.DBConfiguration.Type = dbconfig.InMemoryDB c.ApplicationConfiguration.DBConfiguration.Type = dbconfig.InMemoryDB
} else { } else {
c = *cfg c = *cfg
@ -128,6 +134,10 @@ func newTestVMClIWithState(t *testing.T) *executor {
} }
bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, store) bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, store)
require.NoError(t, err) require.NoError(t, err)
// Save config for future usage.
protoCfg := bc.GetConfig()
go bc.Run() go bc.Run()
e := neotest.NewExecutor(t, bc, validators, committee) e := neotest.NewExecutor(t, bc, validators, committee)
basicchain.InitSimple(t, "../../", e) basicchain.InitSimple(t, "../../", e)
@ -139,7 +149,9 @@ func newTestVMClIWithState(t *testing.T) *executor {
require.NoError(t, err) require.NoError(t, err)
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions = opts cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions = opts
cfg.ProtocolConfiguration.StateRootInHeader = true cfg.ProtocolConfiguration.StateRootInHeader = protoCfg.StateRootInHeader
cfg.ProtocolConfiguration.P2PStateExchangeExtensions = protoCfg.P2PStateExchangeExtensions
cfg.ProtocolConfiguration.Hardforks = protoCfg.Hardforks
return newTestVMCLIWithLogoAndCustomConfig(t, false, &cfg) return newTestVMCLIWithLogoAndCustomConfig(t, false, &cfg)
} }
@ -280,6 +292,95 @@ func (e *executor) checkSlot(t *testing.T, items ...any) {
require.NoError(t, err) require.NoError(t, err)
} }
func TestRun_WithNewVMContextAndBreakpoints(t *testing.T) {
t.Run("contract without init", func(t *testing.T) {
src := `package kek
func Main(a, b int) int {
var c = a + b
return c + 5
}`
tmpDir := t.TempDir()
filename := prepareLoadgoSrc(t, tmpDir, src)
e := newTestVMCLI(t)
e.runProgWithTimeout(t, 10*time.Second,
"loadgo "+filename,
"break 8",
"run main 3 5",
"run",
)
e.checkNextLine(t, "READY: loaded \\d* instructions")
e.checkNextLine(t, "breakpoint added at instruction 8")
e.checkNextLine(t, "at breakpoint 8 (PUSH5)*")
e.checkStack(t, 13)
})
t.Run("contract with init", func(t *testing.T) {
src := `package kek
var I = 5
func Main(a, b int) int {
var c = a + b
return c + I
}`
tmpDir := t.TempDir()
filename := prepareLoadgoSrc(t, tmpDir, src)
e := newTestVMCLI(t)
e.runProgWithTimeout(t, 10*time.Second,
"loadgo "+filename,
"break 10",
"run main 3 5",
"run",
)
e.checkNextLine(t, "READY: loaded \\d* instructions")
e.checkNextLine(t, "breakpoint added at instruction 10")
e.checkNextLine(t, "at breakpoint 10 (ADD)*")
e.checkStack(t, 13)
})
}
// prepareLoadgoSrc prepares provided SC source file for loading into VM via `loadgo` command.
func prepareLoadgoSrc(t *testing.T, tmpDir, src string) string {
filename := filepath.Join(tmpDir, "vmtestcontract.go")
require.NoError(t, os.WriteFile(filename, []byte(src), os.ModePerm))
filename = "'" + filename + "'"
wd, err := os.Getwd()
require.NoError(t, err)
goMod := []byte(`module test.example/kek
require (
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0
)
replace github.com/nspcc-dev/neo-go/pkg/interop => ` + filepath.Join(wd, "../../pkg/interop") + `
go 1.20`)
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "go.mod"), goMod, os.ModePerm))
return filename
}
// prepareLoadnefSrc compiles provided SC source and prepares NEF and manifest for loading into VM
// via `loadnef` command. It returns the name of manifest and NEF files ready to be used in CLI
// commands.
func prepareLoadnefSrc(t *testing.T, tmpDir, src string) (string, string) {
nefFile, di, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
require.NoError(t, err)
filename := filepath.Join(tmpDir, "vmtestcontract.nef")
rawNef, err := nefFile.Bytes()
require.NoError(t, err)
require.NoError(t, os.WriteFile(filename, rawNef, os.ModePerm))
m, err := di.ConvertToManifest(&compiler.Options{})
require.NoError(t, err)
manifestFile := filepath.Join(tmpDir, "vmtestcontract.manifest.json")
rawManifest, err := json.Marshal(m)
require.NoError(t, err)
require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm))
manifestFile = "'" + manifestFile + "'"
filename = "'" + filename + "'"
return manifestFile, filename
}
func TestLoad(t *testing.T) { func TestLoad(t *testing.T) {
script := []byte{byte(opcode.PUSH3), byte(opcode.PUSH4), byte(opcode.ADD)} script := []byte{byte(opcode.PUSH3), byte(opcode.PUSH4), byte(opcode.ADD)}
@ -298,21 +399,27 @@ func TestLoad(t *testing.T) {
"loadhex", "loadhex",
"loadhex notahex", "loadhex notahex",
"loadhex "+hex.EncodeToString(script), "loadhex "+hex.EncodeToString(script),
"loadhex "+hex.EncodeToString(checkWitnessScript)+" "+ownerAddress, // owner:DefaultScope => true "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator,
"loadhex "+hex.EncodeToString(checkWitnessScript)+" "+"not-a-separator",
"loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+"not-a-signer",
"loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAddress, // owner:DefaultScope => true
"run", "run",
"loadhex "+hex.EncodeToString(checkWitnessScript)+" "+ownerAddress+":None", // owner:None => false "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAddress+":None", // owner:None => false
"run", "run",
"loadhex "+hex.EncodeToString(checkWitnessScript)+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true
"run", "run",
"loadhex "+hex.EncodeToString(checkWitnessScript)+" 0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+"0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true
"run", "run",
"loadhex "+hex.EncodeToString(checkWitnessScript)+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false "loadhex "+hex.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false
"run", "run",
) )
e.checkError(t, ErrMissingParameter) e.checkError(t, ErrMissingParameter)
e.checkError(t, ErrInvalidParameter) e.checkError(t, ErrInvalidParameter)
e.checkNextLine(t, "READY: loaded 3 instructions") e.checkNextLine(t, "READY: loaded 3 instructions")
e.checkError(t, ErrInvalidParameter)
e.checkError(t, ErrInvalidParameter)
e.checkError(t, ErrInvalidParameter)
e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkNextLine(t, "READY: loaded \\d+ instructions")
e.checkStack(t, true) e.checkStack(t, true)
e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkNextLine(t, "READY: loaded \\d+ instructions")
@ -330,21 +437,27 @@ func TestLoad(t *testing.T) {
"loadbase64", "loadbase64",
"loadbase64 not_a_base64", "loadbase64 not_a_base64",
"loadbase64 "+base64.StdEncoding.EncodeToString(script), "loadbase64 "+base64.StdEncoding.EncodeToString(script),
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+ownerAddress, // owner:DefaultScope => true "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator,
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+"not-a-separator",
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" not-a-signer",
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAddress, // owner:DefaultScope => true
"run", "run",
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+ownerAddress+":None", // owner:None => false "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAddress+":None", // owner:None => false
"run", "run",
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true
"run", "run",
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" 0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+"0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true
"run", "run",
"loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false "loadbase64 "+base64.StdEncoding.EncodeToString(checkWitnessScript)+" "+cmdargs.CosignersSeparator+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false
"run", "run",
) )
e.checkError(t, ErrMissingParameter) e.checkError(t, ErrMissingParameter)
e.checkError(t, ErrInvalidParameter) e.checkError(t, ErrInvalidParameter)
e.checkNextLine(t, "READY: loaded 3 instructions") e.checkNextLine(t, "READY: loaded 3 instructions")
e.checkError(t, ErrInvalidParameter)
e.checkError(t, ErrInvalidParameter)
e.checkError(t, ErrInvalidParameter)
e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkNextLine(t, "READY: loaded \\d+ instructions")
e.checkStack(t, true) e.checkStack(t, true)
e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkNextLine(t, "READY: loaded \\d+ instructions")
@ -365,19 +478,13 @@ func TestLoad(t *testing.T) {
return a * b return a * b
} }
}` }`
tmpDir := t.TempDir()
checkLoadgo := func(t *testing.T, tName, cName, cErrName string) { t.Run("loadgo", func(t *testing.T) {
t.Run("loadgo "+tName, func(t *testing.T) { tmpDir := t.TempDir()
filename := filepath.Join(tmpDir, cName)
require.NoError(t, os.WriteFile(filename, []byte(src), os.ModePerm)) checkLoadgo := func(t *testing.T, cName, cErrName string) {
filename = "'" + filename + "'" filename := prepareLoadgoSrc(t, tmpDir, src)
filenameErr := filepath.Join(tmpDir, cErrName) filenameErr := filepath.Join(tmpDir, cErrName)
require.NoError(t, os.WriteFile(filenameErr, []byte(src+"invalid_token"), os.ModePerm))
filenameErr = "'" + filenameErr + "'"
goMod := []byte(`module test.example/vmcli
go 1.18`)
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "go.mod"), goMod, os.ModePerm))
e := newTestVMCLI(t) e := newTestVMCLI(t)
e.runProgWithTimeout(t, 10*time.Second, e.runProgWithTimeout(t, 10*time.Second,
@ -390,46 +497,34 @@ go 1.18`)
e.checkNextLine(t, "Error:") e.checkNextLine(t, "Error:")
e.checkNextLine(t, "READY: loaded \\d* instructions") e.checkNextLine(t, "READY: loaded \\d* instructions")
e.checkStack(t, 8) e.checkStack(t, 8)
}
t.Run("simple", func(t *testing.T) {
checkLoadgo(t, "vmtestcontract.go", "vmtestcontract_err.go")
})
t.Run("utf-8 with spaces", func(t *testing.T) {
checkLoadgo(t, "тестовый контракт.go", "тестовый контракт с ошибкой.go")
}) })
}
checkLoadgo(t, "simple", "vmtestcontract.go", "vmtestcontract_err.go") t.Run("check calling flags", func(t *testing.T) {
checkLoadgo(t, "utf-8 with spaces", "тестовый контракт.go", "тестовый контракт с ошибкой.go") srcAllowNotify := `package kek
prepareLoadgoSrc := func(t *testing.T, srcAllowNotify string) string {
filename := filepath.Join(tmpDir, "vmtestcontract.go")
require.NoError(t, os.WriteFile(filename, []byte(srcAllowNotify), os.ModePerm))
filename = "'" + filename + "'"
wd, err := os.Getwd()
require.NoError(t, err)
goMod := []byte(`module test.example/kek
require (
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0
)
replace github.com/nspcc-dev/neo-go/pkg/interop => ` + filepath.Join(wd, "../../pkg/interop") + `
go 1.18`)
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "go.mod"), goMod, os.ModePerm))
return filename
}
t.Run("loadgo, check calling flags", func(t *testing.T) {
srcAllowNotify := `package kek
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime" import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
func Main() int { func Main() int {
runtime.Log("Hello, world!") runtime.Log("Hello, world!")
return 1 return 1
} }
` `
filename := prepareLoadgoSrc(t, srcAllowNotify) filename := prepareLoadgoSrc(t, tmpDir, srcAllowNotify)
e := newTestVMCLI(t) e := newTestVMCLI(t)
e.runProg(t, e.runProg(t,
"loadgo "+filename, "loadgo "+filename,
"run main") "run main")
e.checkNextLine(t, "READY: loaded \\d* instructions") e.checkNextLine(t, "READY: loaded \\d* instructions")
e.checkStack(t, 1) e.checkStack(t, 1)
}) })
t.Run("loadgo, check signers", func(t *testing.T) { t.Run("check signers", func(t *testing.T) {
srcCheckWitness := `package kek srcCheckWitness := `package kek
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/interop/lib/address" "github.com/nspcc-dev/neo-go/pkg/interop/lib/address"
@ -439,71 +534,80 @@ go 1.18`)
return runtime.CheckWitness(owner) return runtime.CheckWitness(owner)
} }
` `
filename := prepareLoadgoSrc(t, srcCheckWitness) filename := prepareLoadgoSrc(t, tmpDir, srcCheckWitness)
t.Run("address", func(t *testing.T) { t.Run("invalid", func(t *testing.T) {
e := newTestVMCLI(t) e := newTestVMCLI(t)
e.runProg(t, e.runProg(t,
"loadgo "+filename+" "+ownerAddress, // owner:DefaultScope => true "loadgo "+filename+" "+cmdargs.CosignersSeparator,
"run main", "loadgo "+filename+" "+"not-a-separator",
"loadgo "+filename+" "+ownerAddress+":None", // owner:None => false "loadgo "+filename+" "+cmdargs.CosignersSeparator+" not-a-signer",
"run main") )
e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkError(t, ErrInvalidParameter)
e.checkStack(t, true) e.checkError(t, ErrInvalidParameter)
e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkError(t, ErrInvalidParameter)
e.checkStack(t, false) })
}) t.Run("address", func(t *testing.T) {
t.Run("string LE", func(t *testing.T) { e := newTestVMCLI(t)
e := newTestVMCLI(t) e.runProg(t,
e.runProg(t, "loadgo "+filename+" "+cmdargs.CosignersSeparator+" "+ownerAddress, // owner:DefaultScope => true
"loadgo "+filename+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true "run main",
"run main", "loadgo "+filename+" "+cmdargs.CosignersSeparator+" "+ownerAddress+":None", // owner:None => false
"loadgo "+filename+" 0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true "run main")
"run main") e.checkNextLine(t, "READY: loaded \\d+ instructions")
e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkStack(t, true)
e.checkStack(t, true) e.checkNextLine(t, "READY: loaded \\d+ instructions")
e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkStack(t, false)
e.checkStack(t, true) })
}) t.Run("string LE", func(t *testing.T) {
t.Run("nonwitnessed signer", func(t *testing.T) { e := newTestVMCLI(t)
e := newTestVMCLI(t) e.runProg(t,
e.runProg(t, "loadgo "+filename+" "+cmdargs.CosignersSeparator+" "+ownerAcc.StringLE(), // ownerLE:DefaultScope => true
"loadgo "+filename+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false "run main",
"run main") "loadgo "+filename+" "+cmdargs.CosignersSeparator+" "+"0x"+ownerAcc.StringLE(), // owner0xLE:DefaultScope => true
e.checkNextLine(t, "READY: loaded \\d+ instructions") "run main")
e.checkStack(t, false) e.checkNextLine(t, "READY: loaded \\d+ instructions")
e.checkStack(t, true)
e.checkNextLine(t, "READY: loaded \\d+ instructions")
e.checkStack(t, true)
})
t.Run("nonwitnessed signer", func(t *testing.T) {
e := newTestVMCLI(t)
e.runProg(t,
"loadgo "+filename+" "+cmdargs.CosignersSeparator+" "+sideAcc.StringLE(), // sideLE:DefaultScope => false
"run main")
e.checkNextLine(t, "READY: loaded \\d+ instructions")
e.checkStack(t, false)
})
}) })
}) })
t.Run("loadnef", func(t *testing.T) { t.Run("loadnef", func(t *testing.T) {
config.Version = "0.92.0-test" tmpDir := t.TempDir()
nefFile, di, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil) manifestFile, nefFile := prepareLoadnefSrc(t, tmpDir, src)
require.NoError(t, err)
filename := filepath.Join(tmpDir, "vmtestcontract.nef")
rawNef, err := nefFile.Bytes()
require.NoError(t, err)
require.NoError(t, os.WriteFile(filename, rawNef, os.ModePerm))
m, err := di.ConvertToManifest(&compiler.Options{})
require.NoError(t, err)
manifestFile := filepath.Join(tmpDir, "vmtestcontract.manifest.json")
rawManifest, err := json.Marshal(m)
require.NoError(t, err)
require.NoError(t, os.WriteFile(manifestFile, rawManifest, os.ModePerm))
filenameErr := filepath.Join(tmpDir, "vmtestcontract_err.nef") filenameErr := filepath.Join(tmpDir, "vmtestcontract_err.nef")
require.NoError(t, os.WriteFile(filenameErr, append([]byte{1, 2, 3, 4}, rawNef...), os.ModePerm)) require.NoError(t, os.WriteFile(filenameErr, []byte{1, 2, 3, 4}, os.ModePerm))
notExists := filepath.Join(tmpDir, "notexists.json") notExists := filepath.Join(tmpDir, "notexists.json")
manifestFile = "'" + manifestFile + "'"
filename = "'" + filename + "'"
filenameErr = "'" + filenameErr + "'" filenameErr = "'" + filenameErr + "'"
e := newTestVMCLI(t) e := newTestVMCLI(t)
e.runProg(t, e.runProg(t,
"loadnef", "loadnef",
"loadnef "+filenameErr+" "+manifestFile, "loadnef "+filenameErr+" "+manifestFile,
"loadnef "+filename+" "+notExists, "loadnef "+nefFile+" "+notExists,
"loadnef "+filename+" "+filename, "loadnef "+nefFile+" "+nefFile,
"loadnef "+filename+" "+manifestFile, "loadnef "+nefFile+" "+manifestFile,
"run main add 3 5") "run main add 3 5",
"loadnef "+nefFile,
"run main add 3 5",
"loadnef "+nefFile+" "+cmdargs.CosignersSeparator,
"loadnef "+nefFile+" "+manifestFile+" "+cmdargs.CosignersSeparator,
"loadnef "+nefFile+" "+manifestFile+" "+"not-a-separator",
"loadnef "+nefFile+" "+cmdargs.CosignersSeparator+" "+util.Uint160{1, 2, 3}.StringLE(),
"run main add 3 5",
"loadnef "+nefFile+" "+manifestFile+" "+cmdargs.CosignersSeparator+" "+util.Uint160{1, 2, 3}.StringLE(),
"run main add 3 5",
)
e.checkError(t, ErrMissingParameter) e.checkError(t, ErrMissingParameter)
e.checkNextLine(t, "Error:") e.checkNextLine(t, "Error:")
@ -511,6 +615,82 @@ go 1.18`)
e.checkNextLine(t, "Error:") e.checkNextLine(t, "Error:")
e.checkNextLine(t, "READY: loaded \\d* instructions") e.checkNextLine(t, "READY: loaded \\d* instructions")
e.checkStack(t, 8) e.checkStack(t, 8)
e.checkNextLine(t, "READY: loaded \\d* instructions")
e.checkStack(t, 8)
e.checkNextLine(t, "Error:") // manifest missing, missing signer after --
e.checkNextLine(t, "Error:") // manifest present, missing signer after --
e.checkNextLine(t, "Error:") // manifest present, invalid separator
e.checkNextLine(t, "READY: loaded \\d* instructions") // manifest missing, signer present, OK
e.checkStack(t, 8)
e.checkNextLine(t, "READY: loaded \\d* instructions") // manifest present, signer present, OK
e.checkStack(t, 8)
})
}
func TestLoad_RunWithCALLT(t *testing.T) {
// Our smart compiler will generate CALLT instruction for the following StdLib call:
src := `package kek
import "github.com/nspcc-dev/neo-go/pkg/interop/native/std"
func Main() int {
return std.Atoi("123", 10)
}`
t.Run("loadgo", func(t *testing.T) {
tmp := t.TempDir()
filename := prepareLoadgoSrc(t, tmp, src)
e := newTestVMCLI(t)
e.runProg(t,
"loadgo "+filename,
"run main",
)
e.checkNextLine(t, "READY: loaded \\d* instructions")
e.checkStack(t, 123)
})
t.Run("loadnef", func(t *testing.T) {
tmpDir := t.TempDir()
manifestFile, nefFile := prepareLoadnefSrc(t, tmpDir, src)
e := newTestVMCLI(t)
e.runProg(t,
"loadnef "+nefFile+" "+manifestFile,
"run main",
)
e.checkNextLine(t, "READY: loaded \\d* instructions")
e.checkStack(t, 123)
})
t.Run("loaddeployed", func(t *testing.T) {
// We'll use `Runtime example` example contract which has a call to native Management
// inside performed via CALLT instruction (`destroy` method).
e := newTestVMClIWithState(t)
var (
cH util.Uint160
cName = "Runtime example"
bc = e.cli.chain
)
for i := int32(1); ; i++ {
h, err := bc.GetContractScriptHash(i)
if err != nil {
break
}
cs := bc.GetContractState(h)
if cs == nil {
break
}
if cs.Manifest.Name == cName {
cH = cs.Hash
break
}
}
require.NotEmpty(t, cH, fmt.Sprintf("failed to locate `%s` example contract with CALLT usage in the simple chain", cName))
e.runProg(t,
"loaddeployed "+cH.StringLE()+" -- NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB:Global", // the contract's owner got from the contract's code.
"run destroy",
"exit",
)
e.checkNextLine(t, "READY: loaded \\d* instructions")
e.checkStack(t) // Nothing on stack, successful execution.
}) })
} }
@ -924,7 +1104,7 @@ func TestRunWithHistoricState(t *testing.T) {
e.checkNextLine(t, "READY: loaded 36 instructions") e.checkNextLine(t, "READY: loaded 36 instructions")
e.checkStack(t, []byte{1}) e.checkStack(t, []byte{1})
e.checkNextLine(t, "READY: loaded 36 instructions") e.checkNextLine(t, "READY: loaded 36 instructions")
e.checkNextLineExact(t, "Error: at instruction 31 (SYSCALL): System.Contract.Call failed: called contract 73a23e915b66ae406866787f4a6c1c517dc981e2 not found: key not found\n") e.checkNextLineExact(t, "Error: at instruction 31 (SYSCALL): System.Contract.Call failed: called contract 0f825b050eb8ce9eaa82993e90615025ab798016 not found: key not found\n")
} }
func TestEvents(t *testing.T) { func TestEvents(t *testing.T) {
@ -1153,24 +1333,27 @@ func TestLoaddeployed(t *testing.T) {
"run get 1", "run get 1",
"loaddeployed --gas 420000 "+h.StringLE(), // gas-limited "loaddeployed --gas 420000 "+h.StringLE(), // gas-limited
"run get 1", "run get 1",
"loaddeployed 0x"+h.StringLE(), // hash LE with 0x prefix "loaddeployed "+"0x"+h.StringLE(), // hash LE with 0x prefix
"run get 1", "run get 1",
"loaddeployed 1", // contract ID "loaddeployed 1", // contract ID
"run get 1", "run get 1",
"loaddeployed --historic 2 1", // historic state, check that hash is properly set "loaddeployed --historic 2 1", // historic state, check that hash is properly set
"run get 1", "run get 1",
// Check signers parsing: // Check signers parsing:
"loaddeployed 2 "+ownerAddress, // check witness (owner:DefautScope => true) "loaddeployed 2 "+cmdargs.CosignersSeparator,
"loaddeployed 2 "+"not-a-separator",
"loaddeployed 2 "+cmdargs.CosignersSeparator+" not-a-signer",
"loaddeployed 2 "+cmdargs.CosignersSeparator+" "+ownerAddress, // check witness (owner:DefautScope => true)
"run checkWitness", "run checkWitness",
"loaddeployed 2 "+ownerAddress+":None", // check witness (owner:None => false) "loaddeployed 2 "+cmdargs.CosignersSeparator+" "+ownerAddress+":None", // check witness (owner:None => false)
"run checkWitness", "run checkWitness",
"loaddeployed 2 "+ownerAddress+":CalledByEntry", // check witness (owner:CalledByEntry => true) "loaddeployed 2 "+cmdargs.CosignersSeparator+" "+ownerAddress+":CalledByEntry", // check witness (owner:CalledByEntry => true)
"run checkWitness", "run checkWitness",
"loaddeployed 2 "+ownerAcc.StringLE()+":CalledByEntry", // check witness (ownerLE:CalledByEntry => true) "loaddeployed 2 "+cmdargs.CosignersSeparator+" "+ownerAcc.StringLE()+":CalledByEntry", // check witness (ownerLE:CalledByEntry => true)
"run checkWitness", "run checkWitness",
"loaddeployed 2 0x"+ownerAcc.StringLE()+":CalledByEntry", // check witness (owner0xLE:CalledByEntry => true) "loaddeployed 2 "+cmdargs.CosignersSeparator+" "+"0x"+ownerAcc.StringLE()+":CalledByEntry", // check witness (owner0xLE:CalledByEntry => true)
"run checkWitness", "run checkWitness",
"loaddeployed 2 "+sideAcc.StringLE()+":Global", // check witness (sideLE:Global => false) "loaddeployed 2 "+cmdargs.CosignersSeparator+" "+sideAcc.StringLE()+":Global", // check witness (sideLE:Global => false)
"run checkWitness", "run checkWitness",
"loaddeployed", // missing argument "loaddeployed", // missing argument
"exit", "exit",
@ -1186,6 +1369,9 @@ func TestLoaddeployed(t *testing.T) {
e.checkNextLine(t, "READY: loaded \\d+ instructions") e.checkNextLine(t, "READY: loaded \\d+ instructions")
e.checkStack(t, []byte{1}) e.checkStack(t, []byte{1})
// Check signers parsing: // Check signers parsing:
e.checkError(t, ErrInvalidParameter)
e.checkError(t, ErrInvalidParameter)
e.checkError(t, ErrInvalidParameter)
e.checkNextLine(t, "READY: loaded \\d+ instructions") // check witness of owner:DefaultScope e.checkNextLine(t, "READY: loaded \\d+ instructions") // check witness of owner:DefaultScope
e.checkStack(t, true) e.checkStack(t, true)
e.checkNextLine(t, "READY: loaded \\d+ instructions") // check witness of owner:None e.checkNextLine(t, "READY: loaded \\d+ instructions") // check witness of owner:None

View file

@ -13,7 +13,7 @@ import (
// NewCommands returns 'vm' command. // NewCommands returns 'vm' command.
func NewCommands() []cli.Command { func NewCommands() []cli.Command {
cfgFlags := []cli.Flag{options.Config} cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
cfgFlags = append(cfgFlags, options.Network...) cfgFlags = append(cfgFlags, options.Network...)
return []cli.Command{{ return []cli.Command{{
Name: "vm", Name: "vm",

View file

@ -1,7 +1,6 @@
package wallet_test package wallet_test
import ( import (
"encoding/hex"
"math/big" "math/big"
"strconv" "strconv"
"testing" "testing"
@ -18,7 +17,7 @@ func TestRegisterCandidate(t *testing.T) {
validatorAddress := testcli.ValidatorPriv.Address() validatorAddress := testcli.ValidatorPriv.Address()
validatorPublic := testcli.ValidatorPriv.PublicKey() validatorPublic := testcli.ValidatorPriv.PublicKey()
validatorHex := hex.EncodeToString(validatorPublic.Bytes()) validatorHex := validatorPublic.StringCompressed()
e.In.WriteString("one\r") e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer", e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
@ -159,4 +158,61 @@ func TestRegisterCandidate(t *testing.T) {
e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress, validatorAddress) e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress, validatorAddress)
e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something") e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")
e.RunWithError(t, "neo-go", "query", "candidates", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something") e.RunWithError(t, "neo-go", "query", "candidates", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")
t.Run("VoteUnvote await", func(t *testing.T) {
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "candidate", "register",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", validatorAddress,
"--force", "--await")
e.CheckAwaitableTxPersisted(t)
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "candidate", "vote",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", validatorAddress,
"--candidate", validatorHex,
"--force",
"--await")
e.CheckAwaitableTxPersisted(t)
b, _ := e.Chain.GetGoverningTokenBalance(testcli.ValidatorPriv.GetScriptHash())
// unvote
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "candidate", "vote",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", validatorAddress,
"--force", "--await")
_, index := e.CheckAwaitableTxPersisted(t)
vs, err = e.Chain.GetEnrollments()
require.Equal(t, 1, len(vs))
require.Equal(t, validatorPublic, vs[0].Key)
require.Equal(t, big.NewInt(0), vs[0].Votes)
// check state
e.Run(t, "neo-go", "query", "voter",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
validatorAddress)
e.CheckNextLine(t, "^\\s*Voted:\\s+"+"null") // no vote.
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
e.CheckNextLine(t, "^\\s*Block\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
e.CheckEOF(t)
})
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "candidate", "unregister",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--address", validatorAddress,
"--force",
"--await")
e.CheckAwaitableTxPersisted(t)
vs, err = e.Chain.GetEnrollments()
require.Equal(t, 0, len(vs))
} }

View file

@ -8,6 +8,7 @@ import (
"errors" "errors"
"os" "os"
"github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
@ -46,7 +47,7 @@ func newWalletV2FromFile(path string, configPath string) (*walletV2, *string, er
} }
var pass *string var pass *string
if len(configPath) != 0 { if len(configPath) != 0 {
cfg, err := ReadWalletConfig(configPath) cfg, err := options.ReadWalletConfig(configPath)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View file

@ -1,12 +1,12 @@
package wallet package wallet
import ( import (
"bytes"
"crypto/elliptic" "crypto/elliptic"
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util/slice"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -36,27 +36,27 @@ func TestParseMultisigContract(t *testing.T) {
testParseMultisigContract(t, s, 1, pub) testParseMultisigContract(t, s, 1, pub)
}) })
t.Run("bad, no check multisig", func(t *testing.T) { t.Run("bad, no check multisig", func(t *testing.T) {
sBad := slice.Copy(s) sBad := bytes.Clone(s)
sBad[len(sBad)-1] ^= 0xFF sBad[len(sBad)-1] ^= 0xFF
testParseMultisigContract(t, sBad, 0) testParseMultisigContract(t, sBad, 0)
}) })
t.Run("bad, invalid number of keys", func(t *testing.T) { t.Run("bad, invalid number of keys", func(t *testing.T) {
sBad := slice.Copy(s) sBad := bytes.Clone(s)
sBad[len(sBad)-2] = opPush1 + 1 sBad[len(sBad)-2] = opPush1 + 1
testParseMultisigContract(t, sBad, 0) testParseMultisigContract(t, sBad, 0)
}) })
t.Run("bad, invalid first instruction", func(t *testing.T) { t.Run("bad, invalid first instruction", func(t *testing.T) {
sBad := slice.Copy(s) sBad := bytes.Clone(s)
sBad[0] = 0xFF sBad[0] = 0xFF
testParseMultisigContract(t, sBad, 0) testParseMultisigContract(t, sBad, 0)
}) })
t.Run("bad, invalid public key", func(t *testing.T) { t.Run("bad, invalid public key", func(t *testing.T) {
sBad := slice.Copy(s) sBad := bytes.Clone(s)
sBad[2] = 0xFF sBad[2] = 0xFF
testParseMultisigContract(t, sBad, 0) testParseMultisigContract(t, sBad, 0)
}) })
t.Run("bad, many sigs", func(t *testing.T) { t.Run("bad, many sigs", func(t *testing.T) {
sBad := slice.Copy(s) sBad := bytes.Clone(s)
sBad[0] = opPush1 + 1 sBad[0] = opPush1 + 1
testParseMultisigContract(t, sBad, 0) testParseMultisigContract(t, sBad, 0)
}) })

View file

@ -8,7 +8,10 @@ import (
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/paramcontext" "github.com/nspcc-dev/neo-go/cli/paramcontext"
"github.com/nspcc-dev/neo-go/cli/txctx"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -17,15 +20,11 @@ func signStoredTransaction(ctx *cli.Context) error {
out = ctx.String("out") out = ctx.String("out")
rpcNode = ctx.String(options.RPCEndpointFlag) rpcNode = ctx.String(options.RPCEndpointFlag)
addrFlag = ctx.Generic("address").(*flags.Address) addrFlag = ctx.Generic("address").(*flags.Address)
aer *state.AppExecResult
) )
if err := cmdargs.EnsureNone(ctx); err != nil { if err := cmdargs.EnsureNone(ctx); err != nil {
return err return err
} }
wall, pass, err := readWallet(ctx)
if err != nil {
return cli.NewExitError(err, 1)
}
defer wall.Close()
pc, err := paramcontext.Read(ctx.String("in")) pc, err := paramcontext.Read(ctx.String("in"))
if err != nil { if err != nil {
@ -35,9 +34,7 @@ func signStoredTransaction(ctx *cli.Context) error {
if !addrFlag.IsSet { if !addrFlag.IsSet {
return cli.NewExitError("address was not provided", 1) return cli.NewExitError("address was not provided", 1)
} }
acc, _, err := options.GetAccFromContext(ctx)
var ch = addrFlag.Uint160()
acc, err := getDecryptedAccount(wall, ch, pass)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -47,20 +44,13 @@ func signStoredTransaction(ctx *cli.Context) error {
return cli.NewExitError("verifiable item is not a transaction", 1) return cli.NewExitError("verifiable item is not a transaction", 1)
} }
signerFound := false if !tx.HasSigner(acc.ScriptHash()) {
for i := range tx.Signers {
if tx.Signers[i].Account == ch {
signerFound = true
break
}
}
if !signerFound {
return cli.NewExitError("tx signers don't contain provided account", 1) return cli.NewExitError("tx signers don't contain provided account", 1)
} }
if acc.CanSign() { if acc.CanSign() {
sign := acc.SignHashable(pc.Network, pc.Verifiable) sign := acc.SignHashable(pc.Network, pc.Verifiable)
if err := pc.AddSignature(ch, acc.Contract, acc.PublicKey(), sign); err != nil { if err := pc.AddSignature(acc.ScriptHash(), acc.Contract, acc.PublicKey(), sign); err != nil {
return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1) return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1)
} }
} else if rpcNode == "" { } else if rpcNode == "" {
@ -98,10 +88,15 @@ func signStoredTransaction(ctx *cli.Context) error {
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1) return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1)
} }
fmt.Fprintln(ctx.App.Writer, res.StringLE()) if ctx.Bool("await") {
return nil version, err := c.GetVersion()
aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", res.StringLE(), err), 1)
}
}
} }
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE()) txctx.DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer)
return nil return nil
} }

View file

@ -1,7 +1,6 @@
package wallet_test package wallet_test
import ( import (
"encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/big" "math/big"
@ -45,9 +44,9 @@ func TestSignMultisigTx(t *testing.T) {
"--wallet", w, "--wallet", w,
"--wif", wif, "--wif", wif,
"--min", "2", "--min", "2",
hex.EncodeToString(pubs[0].Bytes()), pubs[0].StringCompressed(),
hex.EncodeToString(pubs[1].Bytes()), pubs[1].StringCompressed(),
hex.EncodeToString(pubs[2].Bytes())) pubs[2].StringCompressed())
} }
addAccount(wallet1Path, privs[0].WIF()) addAccount(wallet1Path, privs[0].WIF())
addAccount(wallet2Path, privs[1].WIF()) addAccount(wallet2Path, privs[1].WIF())

View file

@ -101,7 +101,7 @@ func newNEP11Commands() []cli.Command {
{ {
Name: "transfer", Name: "transfer",
Usage: "transfer NEP-11 tokens", Usage: "transfer NEP-11 tokens",
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]", UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [--await] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
Action: transferNEP11, Action: transferNEP11,
Flags: transferFlags, Flags: transferFlags,
Description: `Transfers specified NEP-11 token with optional cosigners list attached to Description: `Transfers specified NEP-11 token with optional cosigners list attached to
@ -110,7 +110,8 @@ func newNEP11Commands() []cli.Command {
'contract testinvokefunction' documentation for the details 'contract testinvokefunction' documentation for the details
about cosigners syntax. If no cosigners are given then the about cosigners syntax. If no cosigners are given then the
sender with CalledByEntry scope will be used as the only sender with CalledByEntry scope will be used as the only
signer. signer. If --await flag is set then the command will wait
for the transaction to be included in a block.
`, `,
}, },
{ {

View file

@ -30,6 +30,14 @@ import (
"github.com/urfave/cli" "github.com/urfave/cli"
) )
// transferTarget represents target address, token amount and data for transfer.
type transferTarget struct {
Token util.Uint160
Address util.Uint160
Amount int64
Data any
}
var ( var (
tokenFlag = cli.StringFlag{ tokenFlag = cli.StringFlag{
Name: "token", Name: "token",
@ -62,6 +70,7 @@ var (
txctx.GasFlag, txctx.GasFlag,
txctx.SysGasFlag, txctx.SysGasFlag,
txctx.ForceFlag, txctx.ForceFlag,
txctx.AwaitFlag,
cli.StringFlag{ cli.StringFlag{
Name: "amount", Name: "amount",
Usage: "Amount of asset to send", Usage: "Amount of asset to send",
@ -75,6 +84,7 @@ var (
txctx.GasFlag, txctx.GasFlag,
txctx.SysGasFlag, txctx.SysGasFlag,
txctx.ForceFlag, txctx.ForceFlag,
txctx.AwaitFlag,
}, options.RPC...) }, options.RPC...)
) )
@ -139,20 +149,22 @@ func newNEP17Commands() []cli.Command {
{ {
Name: "transfer", Name: "transfer",
Usage: "transfer NEP-17 tokens", Usage: "transfer NEP-17 tokens",
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]", UsageText: "transfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
Action: transferNEP17, Action: transferNEP17,
Flags: transferFlags, Flags: transferFlags,
Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners
list attached to the transfer. See 'contract testinvokefunction' documentation list attached to the transfer. See 'contract testinvokefunction' documentation
for the details about 'data' parameter and cosigners syntax. If no 'data' is for the details about 'data' parameter and cosigners syntax. If no 'data' is
given then default nil value will be used. If no cosigners are given then the given then default nil value will be used. If no cosigners are given then the
sender with CalledByEntry scope will be used as the only signer. sender with CalledByEntry scope will be used as the only signer. When --await
flag is used, the command waits for the transaction to be included in a block
before exiting.
`, `,
}, },
{ {
Name: "multitransfer", Name: "multitransfer",
Usage: "transfer NEP-17 tokens to multiple recipients", Usage: "transfer NEP-17 tokens to multiple recipients",
UsageText: `multitransfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr>` + UsageText: `multitransfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> --timeout <time> --from <addr>` +
` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]] [-- <cosigner1:Scope> [<cosigner2> [...]]]`, ` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]] [-- <cosigner1:Scope> [<cosigner2> [...]]]`,
Action: multiTransferNEP17, Action: multiTransferNEP17,
Flags: multiTransferFlags, Flags: multiTransferFlags,
@ -514,7 +526,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
acc, err := getDecryptedAccount(wall, from, pass) acc, err := options.GetUnlockedAccount(wall, from, pass)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -522,25 +534,36 @@ func multiTransferNEP17(ctx *cli.Context) error {
gctx, cancel := options.GetTimeoutContext(ctx) gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel() defer cancel()
c, err := options.GetRPCClient(gctx, ctx)
if err != nil {
return cli.NewExitError(err, 1)
}
if ctx.NArg() == 0 { if ctx.NArg() == 0 {
return cli.NewExitError("empty recipients list", 1) return cli.NewExitError("empty recipients list", 1)
} }
var ( var (
recipients []rpcclient.TransferTarget recipients []transferTarget
cosignersOffset = ctx.NArg() cosignersSepPos = ctx.NArg() // `--` position.
) )
cache := make(map[string]*wallet.Token)
for i := 0; i < ctx.NArg(); i++ { for i := 0; i < ctx.NArg(); i++ {
arg := ctx.Args().Get(i) arg := ctx.Args().Get(i)
if arg == cmdargs.CosignersSeparator { if arg == cmdargs.CosignersSeparator {
cosignersOffset = i + 1 cosignersSepPos = i
break break
} }
}
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersSepPos+1)
if extErr != nil {
return extErr
}
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
}
c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts)
if exitErr != nil {
return exitErr
}
cache := make(map[string]*wallet.Token)
for i := 0; i < cosignersSepPos; i++ {
arg := ctx.Args().Get(i)
ss := strings.SplitN(arg, ":", 3) ss := strings.SplitN(arg, ":", 3)
if len(ss) != 3 { if len(ss) != 3 {
return cli.NewExitError("send format must be '<token>:<addr>:<amount>", 1) return cli.NewExitError("send format must be '<token>:<addr>:<amount>", 1)
@ -564,7 +587,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1) return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
} }
recipients = append(recipients, rpcclient.TransferTarget{ recipients = append(recipients, transferTarget{
Token: token.Hash, Token: token.Hash,
Address: addr, Address: addr,
Amount: amount.Int64(), Amount: amount.Int64(),
@ -572,19 +595,6 @@ func multiTransferNEP17(ctx *cli.Context) error {
}) })
} }
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
if extErr != nil {
return extErr
}
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
}
act, err := actor.New(c, signersAccounts)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
}
tx, err := makeMultiTransferNEP17(act, recipients) tx, err := makeMultiTransferNEP17(act, recipients)
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1) return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1)
@ -610,7 +620,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
acc, err := getDecryptedAccount(wall, from, pass) acc, err := options.GetUnlockedAccount(wall, from, pass)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -618,9 +628,22 @@ func transferNEP(ctx *cli.Context, standard string) error {
gctx, cancel := options.GetTimeoutContext(ctx) gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel() defer cancel()
c, err := options.GetRPCClient(gctx, ctx) cosignersOffset, data, extErr := cmdargs.GetDataFromContext(ctx)
if extErr != nil {
return extErr
}
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
if extErr != nil {
return extErr
}
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
}
c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts)
if exitErr != nil {
return exitErr
} }
toFlag := ctx.Generic("to").(*flags.Address) toFlag := ctx.Generic("to").(*flags.Address)
@ -636,24 +659,6 @@ func transferNEP(ctx *cli.Context, standard string) error {
} }
} }
cosignersOffset, data, extErr := cmdargs.GetDataFromContext(ctx)
if extErr != nil {
return extErr
}
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
if extErr != nil {
return extErr
}
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
if err != nil {
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
}
act, err := actor.New(c, signersAccounts)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
}
amountArg := ctx.String("amount") amountArg := ctx.String("amount")
amount, err := fixedn.FromString(amountArg, int(token.Decimals)) amount, err := fixedn.FromString(amountArg, int(token.Decimals))
// It's OK for NEP-11 transfer to not have amount set. // It's OK for NEP-11 transfer to not have amount set.
@ -690,7 +695,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
return txctx.SignAndSend(ctx, act, acc, tx) return txctx.SignAndSend(ctx, act, acc, tx)
} }
func makeMultiTransferNEP17(act *actor.Actor, recipients []rpcclient.TransferTarget) (*transaction.Transaction, error) { func makeMultiTransferNEP17(act *actor.Actor, recipients []transferTarget) (*transaction.Transaction, error) {
scr := smartcontract.NewBuilder() scr := smartcontract.NewBuilder()
for i := range recipients { for i := range recipients {
scr.InvokeWithAssert(recipients[i].Token, "transfer", act.Sender(), scr.InvokeWithAssert(recipients[i].Token, "transfer", act.Sender(),

View file

@ -52,4 +52,4 @@
"extra": { "extra": {
"Tokens": null "Tokens": null
} }
} }

View file

@ -5,13 +5,10 @@ import (
"github.com/nspcc-dev/neo-go/cli/cmdargs" "github.com/nspcc-dev/neo-go/cli/cmdargs"
"github.com/nspcc-dev/neo-go/cli/flags" "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/txctx" "github.com/nspcc-dev/neo-go/cli/txctx"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo" "github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
@ -23,7 +20,7 @@ func newValidatorCommands() []cli.Command {
{ {
Name: "register", Name: "register",
Usage: "register as a new candidate", Usage: "register as a new candidate",
UsageText: "register -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force]", UsageText: "register -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
Action: handleRegister, Action: handleRegister,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
walletPathFlag, walletPathFlag,
@ -32,6 +29,7 @@ func newValidatorCommands() []cli.Command {
txctx.SysGasFlag, txctx.SysGasFlag,
txctx.OutFlag, txctx.OutFlag,
txctx.ForceFlag, txctx.ForceFlag,
txctx.AwaitFlag,
flags.AddressFlag{ flags.AddressFlag{
Name: "address, a", Name: "address, a",
Usage: "Address to register", Usage: "Address to register",
@ -41,7 +39,7 @@ func newValidatorCommands() []cli.Command {
{ {
Name: "unregister", Name: "unregister",
Usage: "unregister self as a candidate", Usage: "unregister self as a candidate",
UsageText: "unregister -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force]", UsageText: "unregister -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
Action: handleUnregister, Action: handleUnregister,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
walletPathFlag, walletPathFlag,
@ -50,6 +48,7 @@ func newValidatorCommands() []cli.Command {
txctx.SysGasFlag, txctx.SysGasFlag,
txctx.OutFlag, txctx.OutFlag,
txctx.ForceFlag, txctx.ForceFlag,
txctx.AwaitFlag,
flags.AddressFlag{ flags.AddressFlag{
Name: "address, a", Name: "address, a",
Usage: "Address to unregister", Usage: "Address to unregister",
@ -59,9 +58,10 @@ func newValidatorCommands() []cli.Command {
{ {
Name: "vote", Name: "vote",
Usage: "vote for a validator", Usage: "vote for a validator",
UsageText: "vote -w <path> -r <rpc> [-s <timeout>] [-g gas] [-e sysgas] -a <addr> [-c <public key>] [--out file] [--force]", UsageText: "vote -w <path> -r <rpc> [-s <timeout>] [-g gas] [-e sysgas] -a <addr> [-c <public key>] [--out file] [--force] [--await]",
Description: `Votes for a validator by calling "vote" method of a NEO native Description: `Votes for a validator by calling "vote" method of a NEO native
contract. Do not provide candidate argument to perform unvoting. contract. Do not provide candidate argument to perform unvoting. If --await flag is
included, the command waits for the transaction to be included in a block before exiting.
`, `,
Action: handleVote, Action: handleVote,
Flags: append([]cli.Flag{ Flags: append([]cli.Flag{
@ -71,6 +71,7 @@ func newValidatorCommands() []cli.Command {
txctx.SysGasFlag, txctx.SysGasFlag,
txctx.OutFlag, txctx.OutFlag,
txctx.ForceFlag, txctx.ForceFlag,
txctx.AwaitFlag,
flags.AddressFlag{ flags.AddressFlag{
Name: "address, a", Name: "address, a",
Usage: "Address to vote from", Usage: "Address to vote from",
@ -111,7 +112,7 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
return cli.NewExitError("address was not provided", 1) return cli.NewExitError("address was not provided", 1)
} }
addr := addrFlag.Uint160() addr := addrFlag.Uint160()
acc, err := getDecryptedAccount(wall, addr, pass) acc, err := options.GetUnlockedAccount(wall, addr, pass)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -119,13 +120,13 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
gctx, cancel := options.GetTimeoutContext(ctx) gctx, cancel := options.GetTimeoutContext(ctx)
defer cancel() defer cancel()
c, err := options.GetRPCClient(gctx, ctx) signers, err := cmdargs.GetSignersAccounts(acc, wall, nil, transaction.CalledByEntry)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
} }
act, err := actor.NewSimple(c, acc) _, act, exitErr := options.GetRPCWithActor(gctx, ctx, signers)
if err != nil { if exitErr != nil {
return cli.NewExitError(fmt.Errorf("RPC actor issue: %w", err), 1) return exitErr
} }
contract := neo.New(act) contract := neo.New(act)
@ -153,32 +154,3 @@ func handleVote(ctx *cli.Context) error {
return contract.VoteUnsigned(addr, pub) return contract.VoteUnsigned(addr, pub)
}) })
} }
// getDecryptedAccount tries to get and unlock the specified account if it has a
// key inside (otherwise it's returned as is, without an ability to sign). If
// password is nil, it will be requested via terminal.
func getDecryptedAccount(wall *wallet.Wallet, addr util.Uint160, password *string) (*wallet.Account, error) {
acc := wall.GetAccount(addr)
if acc == nil {
return nil, fmt.Errorf("can't find account for the address: %s", address.Uint160ToString(addr))
}
// No private key available, nothing to decrypt, but it's still a useful account for many purposes.
if acc.EncryptedWIF == "" {
return acc, nil
}
if password == nil {
pass, err := input.ReadPassword(EnterPasswordPrompt)
if err != nil {
fmt.Println("Error reading password", err)
return nil, err
}
password = &pass
}
err := acc.Decrypt(*password, wall.Scrypt)
if err != nil {
return nil, err
}
return acc, nil
}

View file

@ -15,7 +15,6 @@ import (
"github.com/nspcc-dev/neo-go/cli/input" "github.com/nspcc-dev/neo-go/cli/input"
"github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/options"
"github.com/nspcc-dev/neo-go/cli/txctx" "github.com/nspcc-dev/neo-go/cli/txctx"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
@ -26,7 +25,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/urfave/cli" "github.com/urfave/cli"
"gopkg.in/yaml.v3"
) )
const ( const (
@ -88,6 +86,7 @@ func NewCommands() []cli.Command {
txctx.SysGasFlag, txctx.SysGasFlag,
txctx.OutFlag, txctx.OutFlag,
txctx.ForceFlag, txctx.ForceFlag,
txctx.AwaitFlag,
flags.AddressFlag{ flags.AddressFlag{
Name: "address, a", Name: "address, a",
Usage: "Address to claim GAS for", Usage: "Address to claim GAS for",
@ -98,6 +97,7 @@ func NewCommands() []cli.Command {
walletPathFlag, walletPathFlag,
walletConfigFlag, walletConfigFlag,
txctx.OutFlag, txctx.OutFlag,
txctx.AwaitFlag,
inFlag, inFlag,
flags.AddressFlag{ flags.AddressFlag{
Name: "address, a", Name: "address, a",
@ -112,7 +112,7 @@ func NewCommands() []cli.Command {
{ {
Name: "claim", Name: "claim",
Usage: "claim GAS", Usage: "claim GAS",
UsageText: "neo-go wallet claim -w wallet [--wallet-config path] [-g gas] [-e sysgas] -a address -r endpoint [-s timeout] [--out file] [--force]", UsageText: "neo-go wallet claim -w wallet [--wallet-config path] [-g gas] [-e sysgas] -a address -r endpoint [-s timeout] [--out file] [--force] [--await]",
Action: claimGas, Action: claimGas,
Flags: claimFlags, Flags: claimFlags,
}, },
@ -236,8 +236,15 @@ func NewCommands() []cli.Command {
{ {
Name: "import-multisig", Name: "import-multisig",
Usage: "import multisig contract", Usage: "import multisig contract",
UsageText: "import-multisig -w wallet [--wallet-config path] --wif <wif> [--name <account_name>] --min <n>" + UsageText: "import-multisig -w wallet [--wallet-config path] [--wif <wif>] [--name <account_name>] --min <m>" +
" [<pubkey1> [<pubkey2> [...]]]", " [<pubkey1> [<pubkey2> [...]]]",
Description: `Imports a standard multisignature contract with "m out of n" signatures required where "m" is
specified by --min flag and "n" is the length of provided set of public keys. If
--wif flag is provided, it's used to create an account with the given name (or
without a name if --name flag is not provided). Otherwise, the command tries to
find an account with one of the given public keys and convert it to multisig. If
no suitable account is found and no --wif flag is specified, an error is returned.
`,
Action: importMultisig, Action: importMultisig,
Flags: []cli.Flag{ Flags: []cli.Flag{
walletPathFlag, walletPathFlag,
@ -290,13 +297,15 @@ func NewCommands() []cli.Command {
{ {
Name: "sign", Name: "sign",
Usage: "cosign transaction with multisig/contract/additional account", Usage: "cosign transaction with multisig/contract/additional account",
UsageText: "sign -w wallet [--wallet-config path] --address <address> --in <file.in> [--out <file.out>] [-r <endpoint>]", UsageText: "sign -w wallet [--wallet-config path] --address <address> --in <file.in> [--out <file.out>] [-r <endpoint>] [--await]",
Description: `Signs the given (in file.in) context (which must be a transaction Description: `Signs the given (in file.in) context (which must be a transaction
signing context) for the given address using the given wallet. This command can signing context) for the given address using the given wallet. This command can
output the resulting JSON (with additional signature added) right to the console output the resulting JSON (with additional signature added) right to the console
(if no file.out and no RPC endpoint specified) or into a file (which can be the (if no file.out and no RPC endpoint specified) or into a file (which can be the
same as input one). If an RPC endpoint is given it'll also try to construct a same as input one). If an RPC endpoint is given it'll also try to construct a
complete transaction and send it via RPC (printing its hash if everything is OK). complete transaction and send it via RPC (printing its hash if everything is OK).
If the --await (with a given RPC endpoint) flag is included, the command waits
for the transaction to be included in a block before exiting.
`, `,
Action: signStoredTransaction, Action: signStoredTransaction,
Flags: signFlags, Flags: signFlags,
@ -519,6 +528,12 @@ loop:
} }
func importMultisig(ctx *cli.Context) error { func importMultisig(ctx *cli.Context) error {
var (
label *string
acc *wallet.Account
accPub *keys.PublicKey
)
wall, pass, err := openWallet(ctx, true) wall, pass, err := openWallet(ctx, true)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
@ -540,12 +555,45 @@ func importMultisig(ctx *cli.Context) error {
} }
} }
var label *string
if ctx.IsSet("name") { if ctx.IsSet("name") {
l := ctx.String("name") l := ctx.String("name")
label = &l label = &l
} }
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass)
loop:
for _, pub := range pubs {
for _, wallAcc := range wall.Accounts {
if wallAcc.ScriptHash().Equals(pub.GetScriptHash()) {
if acc != nil {
// Multiple matching accounts found, fallback to WIF-based conversion.
acc = nil
break loop
}
acc = new(wallet.Account)
*acc = *wallAcc
accPub = pub
}
}
}
if acc != nil {
err = acc.ConvertMultisigEncrypted(accPub, m, pubs)
if err != nil {
return cli.NewExitError(err, 1)
}
if label != nil {
acc.Label = *label
}
if err := addAccountAndSave(wall, acc); err != nil {
return cli.NewExitError(err, 1)
}
return nil
}
if !ctx.IsSet("wif") {
return cli.NewExitError(errors.New("none of the provided public keys correspond to an existing key in the wallet or multiple matching accounts found in the wallet, and no WIF is provided"), 1)
}
acc, err = newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -603,7 +651,8 @@ func importDeployed(ctx *cli.Context) error {
return cli.NewExitError("contract has no `verify` method with boolean return", 1) return cli.NewExitError("contract has no `verify` method with boolean return", 1)
} }
acc.Address = address.Uint160ToString(cs.Hash) acc.Address = address.Uint160ToString(cs.Hash)
acc.Contract.Script = cs.NEF.Script // Explicitly overwrite single signature script of the provided WIF since the contract is known to be deployed.
acc.Contract.Script = nil
acc.Contract.Parameters = acc.Contract.Parameters[:0] acc.Contract.Parameters = acc.Contract.Parameters[:0]
for _, p := range md.Parameters { for _, p := range md.Parameters {
acc.Contract.Parameters = append(acc.Contract.Parameters, wallet.ContractParam{ acc.Contract.Parameters = append(acc.Contract.Parameters, wallet.ContractParam{
@ -822,7 +871,7 @@ func createWallet(ctx *cli.Context) error {
} }
var pass *string var pass *string
if len(configPath) != 0 { if len(configPath) != 0 {
cfg, err := ReadWalletConfig(configPath) cfg, err := options.ReadWalletConfig(configPath)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -900,14 +949,14 @@ func createAccount(wall *wallet.Wallet, pass *string) error {
func openWallet(ctx *cli.Context, canUseWalletConfig bool) (*wallet.Wallet, *string, error) { func openWallet(ctx *cli.Context, canUseWalletConfig bool) (*wallet.Wallet, *string, error) {
path, pass, err := getWalletPathAndPass(ctx, canUseWalletConfig) path, pass, err := getWalletPathAndPass(ctx, canUseWalletConfig)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, cli.NewExitError(fmt.Errorf("failed to get wallet path or password: %w", err), 1)
} }
if path == "-" { if path == "-" {
return nil, nil, errNoStdin return nil, nil, errNoStdin
} }
w, err := wallet.NewWalletFromFile(path) w, err := wallet.NewWalletFromFile(path)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, cli.NewExitError(fmt.Errorf("failed to read wallet: %w", err), 1)
} }
return w, pass, nil return w, pass, nil
} }
@ -946,7 +995,7 @@ func getWalletPathAndPass(ctx *cli.Context, canUseWalletConfig bool) (string, *s
} }
var pass *string var pass *string
if len(configPath) != 0 { if len(configPath) != 0 {
cfg, err := ReadWalletConfig(configPath) cfg, err := options.ReadWalletConfig(configPath)
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
@ -956,27 +1005,6 @@ func getWalletPathAndPass(ctx *cli.Context, canUseWalletConfig bool) (string, *s
return path, pass, nil return path, pass, nil
} }
func ReadWalletConfig(configPath string) (*config.Wallet, error) {
file, err := os.Open(configPath)
if err != nil {
return nil, err
}
defer file.Close()
configData, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("unable to read wallet config: %w", err)
}
cfg := &config.Wallet{}
err = yaml.Unmarshal(configData, &cfg)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal wallet config YAML: %w", err)
}
return cfg, nil
}
func newAccountFromWIF(w io.Writer, wif string, scrypt keys.ScryptParams, label *string, pass *string) (*wallet.Account, error) { func newAccountFromWIF(w io.Writer, wif string, scrypt keys.ScryptParams, label *string, pass *string) (*wallet.Account, error) {
var ( var (
phrase, name string phrase, name string

View file

@ -1,7 +1,6 @@
package wallet_test package wallet_test
import ( import (
"encoding/hex"
"encoding/json" "encoding/json"
"math/big" "math/big"
"os" "os"
@ -437,16 +436,16 @@ func TestWalletInit(t *testing.T) {
"--wallet", walletPath, "--wallet", walletPath,
"--min", "2"} "--min", "2"}
t.Run("invalid pub encoding", func(t *testing.T) { t.Run("invalid pub encoding", func(t *testing.T) {
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()), e.RunWithError(t, append(cmd, pubs[1].StringCompressed(),
hex.EncodeToString(pubs[1].Bytes()), pubs[1].StringCompressed(),
hex.EncodeToString(pubs[2].Bytes()), pubs[2].StringCompressed(),
"not-a-pub")...) "not-a-pub")...)
}) })
t.Run("missing WIF", func(t *testing.T) { t.Run("missing WIF", func(t *testing.T) {
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()), e.RunWithError(t, append(cmd, pubs[0].StringCompressed(),
hex.EncodeToString(pubs[1].Bytes()), pubs[1].StringCompressed(),
hex.EncodeToString(pubs[2].Bytes()), pubs[2].StringCompressed(),
hex.EncodeToString(pubs[3].Bytes()))...) pubs[3].StringCompressed())...)
}) })
cmd = append(cmd, "--wif", privs[0].WIF()) cmd = append(cmd, "--wif", privs[0].WIF())
t.Run("InvalidPublicKeys", func(t *testing.T) { t.Run("InvalidPublicKeys", func(t *testing.T) {
@ -455,18 +454,18 @@ func TestWalletInit(t *testing.T) {
e.In.WriteString("multipass\r") e.In.WriteString("multipass\r")
defer e.In.Reset() defer e.In.Reset()
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()), e.RunWithError(t, append(cmd, pubs[1].StringCompressed(),
hex.EncodeToString(pubs[1].Bytes()), pubs[1].StringCompressed(),
hex.EncodeToString(pubs[2].Bytes()), pubs[2].StringCompressed(),
hex.EncodeToString(pubs[3].Bytes()))...) pubs[3].StringCompressed())...)
}) })
e.In.WriteString("multiacc\r") e.In.WriteString("multiacc\r")
e.In.WriteString("multipass\r") e.In.WriteString("multipass\r")
e.In.WriteString("multipass\r") e.In.WriteString("multipass\r")
e.Run(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()), e.Run(t, append(cmd, pubs[0].StringCompressed(),
hex.EncodeToString(pubs[1].Bytes()), pubs[1].StringCompressed(),
hex.EncodeToString(pubs[2].Bytes()), pubs[2].StringCompressed(),
hex.EncodeToString(pubs[3].Bytes()))...) pubs[3].StringCompressed())...)
script, err := smartcontract.CreateMultiSigRedeemScript(2, pubs) script, err := smartcontract.CreateMultiSigRedeemScript(2, pubs)
require.NoError(t, err) require.NoError(t, err)
@ -482,10 +481,62 @@ func TestWalletInit(t *testing.T) {
e.In.WriteString("multiacc\r") e.In.WriteString("multiacc\r")
e.In.WriteString("multipass\r") e.In.WriteString("multipass\r")
e.In.WriteString("multipass\r") e.In.WriteString("multipass\r")
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()), e.RunWithError(t, append(cmd, pubs[0].StringCompressed(),
hex.EncodeToString(pubs[1].Bytes()), pubs[1].StringCompressed(),
hex.EncodeToString(pubs[2].Bytes()), pubs[2].StringCompressed(),
hex.EncodeToString(pubs[3].Bytes()))...) pubs[3].StringCompressed())...)
})
privs, pubs = testcli.GenerateKeys(t, 3)
script, err = smartcontract.CreateMultiSigRedeemScript(2, pubs)
require.NoError(t, err)
// Create a wallet and import a standard account
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
e.In.WriteString("standardacc\rstdpass\rstdpass\r")
e.Run(t, "neo-go", "wallet", "import",
"--wallet", walletPath,
"--wif", privs[0].WIF())
w, err = wallet.NewWalletFromFile(walletPath)
require.NoError(t, err)
actual = w.GetAccount(privs[0].GetScriptHash())
require.NotNil(t, actual)
require.NotEqual(t, actual.Contract.Script, script)
// Test when a public key of an already imported account is present
t.Run("existing account public key, no WIF", func(t *testing.T) {
e.Run(t, "neo-go", "wallet", "import-multisig",
"--wallet", walletPath,
"--min", "2",
pubs[0].StringCompressed(), // Public key of the already imported account
pubs[1].StringCompressed(),
pubs[2].StringCompressed())
w, err := wallet.NewWalletFromFile(walletPath)
require.NoError(t, err)
actual := w.GetAccount(hash.Hash160(script))
require.NotNil(t, actual)
require.Equal(t, actual.Contract.Script, script)
require.NoError(t, actual.Decrypt("stdpass", w.Scrypt))
require.NotEqual(t, actual.Address, w.GetAccount(privs[0].GetScriptHash()).Address)
})
// Test when no public key of an already imported account is present, and no WIF is provided
t.Run("no existing account public key, no WIF", func(t *testing.T) {
_, pubsNew := testcli.GenerateKeys(t, 3)
scriptNew, err := smartcontract.CreateMultiSigRedeemScript(2, pubsNew)
require.NoError(t, err)
e.RunWithError(t, "neo-go", "wallet", "import-multisig",
"--wallet", walletPath,
"--min", "2",
pubsNew[0].StringCompressed(),
pubsNew[1].StringCompressed(),
pubsNew[2].StringCompressed())
w, err := wallet.NewWalletFromFile(walletPath)
require.NoError(t, err)
actual := w.GetAccount(hash.Hash160(scriptNew))
require.Nil(t, actual)
}) })
}) })
}) })
@ -605,6 +656,47 @@ func TestWalletClaimGas(t *testing.T) {
} else { } else {
require.Equal(t, 1, balanceAfter.Cmp(balanceBefore)) require.Equal(t, 1, balanceAfter.Cmp(balanceBefore))
} }
t.Run("await", func(t *testing.T) {
args := []string{
"neo-go", "wallet", "nep17", "multitransfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", testcli.ValidatorWallet,
"--from", testcli.ValidatorAddr, "--await",
"--force",
"NEO:" + testcli.TestWalletAccount + ":1000",
"GAS:" + testcli.TestWalletAccount + ":1000", // for tx send
}
e.In.WriteString("one\r")
e.Run(t, args...)
e.CheckAwaitableTxPersisted(t)
h, err := address.StringToUint160(testcli.TestWalletAccount)
require.NoError(t, err)
balanceBefore := e.Chain.GetUtilityTokenBalance(h)
claimHeight := e.Chain.BlockHeight() + 1
cl, err := e.Chain.CalculateClaimable(h, claimHeight)
require.NoError(t, err)
require.True(t, cl.Sign() > 0)
e.In.WriteString("testpass\r")
e.Run(t, "neo-go", "wallet", "claim",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", testcli.TestWalletPath,
"--address", testcli.TestWalletAccount,
"--force", "--await")
tx, height = e.CheckAwaitableTxPersisted(t)
balanceBefore.Sub(balanceBefore, big.NewInt(tx.NetworkFee+tx.SystemFee))
balanceBefore.Add(balanceBefore, cl)
balanceAfter = e.Chain.GetUtilityTokenBalance(h)
// height can be bigger than claimHeight especially when tests are executed with -race.
if height == claimHeight {
require.Equal(t, 0, balanceAfter.Cmp(balanceBefore))
} else {
require.Equal(t, 1, balanceAfter.Cmp(balanceBefore))
}
})
} }
func TestWalletImportDeployed(t *testing.T) { func TestWalletImportDeployed(t *testing.T) {
@ -822,6 +914,31 @@ func TestOfflineSigning(t *testing.T) {
"--in", txPath) "--in", txPath)
}) })
e.CheckTxPersisted(t) e.CheckTxPersisted(t)
t.Run("await 1/1 multisig", func(t *testing.T) {
args := []string{"neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", walletPath,
"--from", testcli.ValidatorAddr,
"--to", w.Accounts[0].Address,
"--token", "NEO",
"--amount", "1",
"--force",
}
e.Run(t, append(args, "--out", txPath)...)
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "sign",
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
"--in", txPath, "--out", txPath)
e.Run(t, "neo-go", "wallet", "sign",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
"--wallet", walletPath, "--address", testcli.ValidatorAddr,
"--in", txPath, "--await")
e.CheckAwaitableTxPersisted(t)
})
t.Run("simple signature", func(t *testing.T) { t.Run("simple signature", func(t *testing.T) {
simpleAddr := w.Accounts[0].Address simpleAddr := w.Accounts[0].Address
args := []string{"neo-go", "wallet", "nep17", "transfer", args := []string{"neo-go", "wallet", "nep17", "transfer",
@ -853,6 +970,31 @@ func TestOfflineSigning(t *testing.T) {
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
txPath) txPath)
}) })
t.Run("await simple signature", func(t *testing.T) {
simpleAddr := w.Accounts[0].Address
args := []string{"neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
"--wallet", walletPath,
"--from", simpleAddr,
"--to", testcli.ValidatorAddr,
"--token", "NEO",
"--amount", "1",
"--force",
}
e.Run(t, append(args, "--out", txPath)...)
e.In.WriteString("one\r")
e.Run(t, "neo-go", "wallet", "sign",
"--wallet", testcli.ValidatorWallet, "--address", simpleAddr,
"--in", txPath, "--out", txPath)
e.Run(t, "neo-go", "util", "sendtx",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
txPath, "--await")
e.CheckAwaitableTxPersisted(t)
})
} }
func TestWalletDump(t *testing.T) { func TestWalletDump(t *testing.T) {

View file

@ -22,19 +22,11 @@ ProtocolConfiguration:
- morph6.fs.neo.org:40333 - morph6.fs.neo.org:40333
- morph7.fs.neo.org:40333 - morph7.fs.neo.org:40333
VerifyTransactions: true VerifyTransactions: true
P2PSigExtensions: false P2PSigExtensions: true
Hardforks: Hardforks:
Aspidochelone: 3000000 Aspidochelone: 3000000
NativeActivations: Basilisk: 4500000
ContractManagement: [0] Cockatrice: 5800000
StdLib: [0]
CryptoLib: [0]
LedgerContract: [0]
NeoToken: [0]
GasToken: [0]
PolicyContract: [0]
RoleManagement: [0]
OracleContract: [0]
ApplicationConfiguration: ApplicationConfiguration:
SkipBlockVerification: false SkipBlockVerification: false

View file

@ -37,16 +37,8 @@ ProtocolConfiguration:
P2PSigExtensions: false P2PSigExtensions: false
Hardforks: Hardforks:
Aspidochelone: 1730000 Aspidochelone: 1730000
NativeActivations: Basilisk: 4120000
ContractManagement: [0] Cockatrice: 5450000
StdLib: [0]
CryptoLib: [0]
LedgerContract: [0]
NeoToken: [0]
GasToken: [0]
PolicyContract: [0]
RoleManagement: [0]
OracleContract: [0]
ApplicationConfiguration: ApplicationConfiguration:
SkipBlockVerification: false SkipBlockVerification: false

Some files were not shown because too many files have changed in this diff Show more