mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-23 23:30:54 +00:00
Compare commits
524 Commits
pratik/ote
...
xrplf/smar
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
809d92f23a | ||
|
|
5ae09518b8 | ||
|
|
3ab800bf47 | ||
|
|
fe1436fb3e | ||
|
|
abfa572370 | ||
|
|
d8e44687bf | ||
|
|
8a3363752f | ||
|
|
226ec160bb | ||
|
|
ef438aec26 | ||
|
|
6cf743dad9 | ||
|
|
52d2008797 | ||
|
|
4d685d4bad | ||
|
|
75fac65e27 | ||
|
|
ecae6b6346 | ||
|
|
6f4fe178dd | ||
|
|
083986ab82 | ||
|
|
c145201538 | ||
|
|
4fbbd6ff59 | ||
|
|
39c95fee3b | ||
|
|
db6fe77959 | ||
|
|
be58ec0cd5 | ||
|
|
4073838f66 | ||
|
|
e227e2ce8b | ||
|
|
383a2f8819 | ||
|
|
e64703b151 | ||
|
|
c91640e3ac | ||
|
|
0ceee3a013 | ||
|
|
974b17f427 | ||
|
|
91de196312 | ||
|
|
ac71553abe | ||
|
|
9a8ec56d42 | ||
|
|
cb6dad0bc4 | ||
|
|
d54ca4cd3b | ||
|
|
5a0269aca7 | ||
|
|
0774ca32a9 | ||
|
|
8feb75011e | ||
|
|
088c5b3b03 | ||
|
|
1c4abe8c5e | ||
|
|
91a5747bf9 | ||
|
|
bc892f0bd3 | ||
|
|
8950530b04 | ||
|
|
5cbebf3c58 | ||
|
|
c634c75aee | ||
|
|
9801c23bad | ||
|
|
f6472347e9 | ||
|
|
a41889df31 | ||
|
|
2e48bb4b7f | ||
|
|
9e427ae3ba | ||
|
|
8022fc33cf | ||
|
|
9767d86de4 | ||
|
|
ca2d999618 | ||
|
|
4a01fe5aa6 | ||
|
|
f60a9f1c64 | ||
|
|
5ee903befc | ||
|
|
68f0dcae53 | ||
|
|
d582ae7990 | ||
|
|
0dbe51c740 | ||
|
|
63fff4b518 | ||
|
|
d3550fac60 | ||
|
|
10ef15fff1 | ||
|
|
2307cfdc5a | ||
|
|
3b328cfc45 | ||
|
|
e20b2430ba | ||
|
|
99072fbddf | ||
|
|
059cefa35a | ||
|
|
a2205190a6 | ||
|
|
4c657bc92e | ||
|
|
ac481a0bd7 | ||
|
|
7eacd9d735 | ||
|
|
1f9675d22f | ||
|
|
029fa435ee | ||
|
|
c92ca426bf | ||
|
|
ff896b226a | ||
|
|
3c53c94e7a | ||
|
|
d85bf722ea | ||
|
|
b664989cfb | ||
|
|
e77934302a | ||
|
|
ef7aeca6bf | ||
|
|
eec1d29b92 | ||
|
|
971ba2281e | ||
|
|
90357eeae1 | ||
|
|
597202a6f0 | ||
|
|
1600b3e7f3 | ||
|
|
d411448739 | ||
|
|
ecee732187 | ||
|
|
ce2586c039 | ||
|
|
36fb84926e | ||
|
|
56decaf852 | ||
|
|
d562129e7c | ||
|
|
1d9fe9dbaf | ||
|
|
e6eb6ccf6c | ||
|
|
5351d4f089 | ||
|
|
8cc2169939 | ||
|
|
74beb5f80d | ||
|
|
a4dfdaf77a | ||
|
|
826f613ad8 | ||
|
|
1259c1d5ca | ||
|
|
4bae4d781f | ||
|
|
01a5e07830 | ||
|
|
34522bc668 | ||
|
|
d2641d85bd | ||
|
|
75f66bd9fe | ||
|
|
7cd71cb659 | ||
|
|
9917f96166 | ||
|
|
e1cc82587b | ||
|
|
2cc9439fde | ||
|
|
52af9582e2 | ||
|
|
46e88dc732 | ||
|
|
bc24f2e211 | ||
|
|
7a7c993b15 | ||
|
|
9733ca8f91 | ||
|
|
18d5e3e226 | ||
|
|
b30b4e1d65 | ||
|
|
d435893602 | ||
|
|
00b0cf50f6 | ||
|
|
42cbecb9e4 | ||
|
|
fe2e5ce649 | ||
|
|
6afa51142d | ||
|
|
22054a573d | ||
|
|
7ef256499c | ||
|
|
1338062be7 | ||
|
|
4fc1778ec8 | ||
|
|
65322d9e78 | ||
|
|
0acfa1c4f2 | ||
|
|
309fdfc3f2 | ||
|
|
63bd5fc4ee | ||
|
|
82e7f7eeec | ||
|
|
c5598a4284 | ||
|
|
63d09f9c51 | ||
|
|
0deb6bcadf | ||
|
|
d606f88e84 | ||
|
|
9b013b559b | ||
|
|
1d4a3c00b8 | ||
|
|
4b34102e8e | ||
|
|
d006433579 | ||
|
|
a7ab8ee923 | ||
|
|
e0073a4402 | ||
|
|
2930ef217f | ||
|
|
9dbb301699 | ||
|
|
531e8b6ebd | ||
|
|
90397e1a52 | ||
|
|
888ca2e6d9 | ||
|
|
f8a149c675 | ||
|
|
51458a92e2 | ||
|
|
b6514b680f | ||
|
|
913e4b919e | ||
|
|
196e6a1b27 | ||
|
|
27468ddbcf | ||
|
|
bce5d91e45 | ||
|
|
780380da7e | ||
|
|
654338fa66 | ||
|
|
fdfdf4fceb | ||
|
|
a76bd834b6 | ||
|
|
864d88a3c2 | ||
|
|
9c25d18851 | ||
|
|
3a825a41e1 | ||
|
|
a9ebf786c6 | ||
|
|
5afe8cc321 | ||
|
|
bc5ec3c962 | ||
|
|
7004d216ed | ||
|
|
1775251e90 | ||
|
|
61bcb7621f | ||
|
|
a3f71b1774 | ||
|
|
4df7d1a4bb | ||
|
|
50a74b899d | ||
|
|
00eeab6d44 | ||
|
|
125df7a425 | ||
|
|
b08bcf5d21 | ||
|
|
dc413aef0c | ||
|
|
77dfd56ace | ||
|
|
953b9a3500 | ||
|
|
1d9ec84350 | ||
|
|
0392846a17 | ||
|
|
5148098079 | ||
|
|
1b4a564369 | ||
|
|
fd524c4be9 | ||
|
|
495dda7f58 | ||
|
|
9c3c0280b1 | ||
|
|
f73d8a6cf2 | ||
|
|
4fe508cb92 | ||
|
|
6728ab52b7 | ||
|
|
446ad36cbb | ||
|
|
eb2d44d442 | ||
|
|
77673663ca | ||
|
|
c1381f8ddd | ||
|
|
bd16f7989d | ||
|
|
fd14054f17 | ||
|
|
65f9cf80c0 | ||
|
|
4318b2ebf7 | ||
|
|
e6ee492822 | ||
|
|
d4510147d1 | ||
|
|
a9a94fbf1a | ||
|
|
719ba392db | ||
|
|
cd46b5d999 | ||
|
|
de55a5ebfc | ||
|
|
2ec4a1114e | ||
|
|
f01ac563a9 | ||
|
|
13707dda05 | ||
|
|
ba03a8a9d2 | ||
|
|
7c8279ec83 | ||
|
|
a1844086d7 | ||
|
|
f625fb993a | ||
|
|
0418ffb26a | ||
|
|
b2627039f6 | ||
|
|
8f97ec3bde | ||
|
|
e85e7b1b1a | ||
|
|
ac173b6827 | ||
|
|
69c61b2235 | ||
|
|
6ae0e860ff | ||
|
|
c077e7f073 | ||
|
|
803a344c65 | ||
|
|
4eb34f381a | ||
|
|
72fffb6e51 | ||
|
|
f7ee580f01 | ||
|
|
122d405750 | ||
|
|
c1c1b4ea67 | ||
|
|
977caea0a5 | ||
|
|
d7ed6d6512 | ||
|
|
f1f2e2629f | ||
|
|
917c610f96 | ||
|
|
317e533d81 | ||
|
|
4160677878 | ||
|
|
430696682d | ||
|
|
4621e4eda3 | ||
|
|
df98db1452 | ||
|
|
981ac7abf4 | ||
|
|
57d2a91ad5 | ||
|
|
673476ef1b | ||
|
|
8bc6f9cd70 | ||
|
|
ba5debfecd | ||
|
|
f4a27c9b6d | ||
|
|
fd1cb318e3 | ||
|
|
94b35a234e | ||
|
|
b5d0078927 | ||
|
|
43c80edaf4 | ||
|
|
8c3544a58c | ||
|
|
ed5139d4e3 | ||
|
|
42494dd4cf | ||
|
|
ce84cc8b44 | ||
|
|
9a9a7aab01 | ||
|
|
209a1a6ffa | ||
|
|
9538e9b34c | ||
|
|
384b3608d7 | ||
|
|
fc35a9f9c8 | ||
|
|
c5e50aa221 | ||
|
|
074b1f00d5 | ||
|
|
7a9d245950 | ||
|
|
1809fe07f2 | ||
|
|
409c67494a | ||
|
|
fb97f7b596 | ||
|
|
c626b6403a | ||
|
|
81cbc91927 | ||
|
|
845c503ea6 | ||
|
|
e1513570df | ||
|
|
1c812a6c4d | ||
|
|
0724927799 | ||
|
|
ff39fa59d9 | ||
|
|
d83ec96848 | ||
|
|
f0d0739528 | ||
|
|
375dd50b35 | ||
|
|
419d53ec4c | ||
|
|
d4d70d5675 | ||
|
|
6ab15f8377 | ||
|
|
91f3d51f3d | ||
|
|
9ed60b45f8 | ||
|
|
d5c53dcfd2 | ||
|
|
8015088340 | ||
|
|
103379836a | ||
|
|
e94321fb41 | ||
|
|
bbc28b3b1c | ||
|
|
843e981c8a | ||
|
|
5aab274b7a | ||
|
|
2c30e41191 | ||
|
|
8ea5106b0b | ||
|
|
f57f67a8ae | ||
|
|
61b2fe4f64 | ||
|
|
7ee964f514 | ||
|
|
397bc8781e | ||
|
|
a98269f049 | ||
|
|
8bb8c2e38b | ||
|
|
b66bc47ca9 | ||
|
|
0e9c7458bb | ||
|
|
36ecd3b52b | ||
|
|
1d89940653 | ||
|
|
1a1a6806ec | ||
|
|
1977df9c2e | ||
|
|
6ffbef09c2 | ||
|
|
e05f907788 | ||
|
|
9d1f51b01a | ||
|
|
6c95548df5 | ||
|
|
69ab39d658 | ||
|
|
b9eb66eecc | ||
|
|
e916416642 | ||
|
|
827ecc6e3a | ||
|
|
6a54ed7f14 | ||
|
|
881087dd3d | ||
|
|
90e0bbd0fc | ||
|
|
b57df290de | ||
|
|
8a403f1241 | ||
|
|
1e0741690d | ||
|
|
6d2640871d | ||
|
|
c5d178f152 | ||
|
|
5a17940e2a | ||
|
|
27ac30208d | ||
|
|
c145598ff9 | ||
|
|
50e5608d86 | ||
|
|
abfcc4ef67 | ||
|
|
e40a4df777 | ||
|
|
dba187f8c5 | ||
|
|
7a7b96107c | ||
|
|
8f2f8d53b4 | ||
|
|
49acc61961 | ||
|
|
500bb68831 | ||
|
|
95d78a8600 | ||
|
|
53eb0f60bc | ||
|
|
41205ae928 | ||
|
|
c33b0ae463 | ||
|
|
16087c9680 | ||
|
|
56bc6d58f6 | ||
|
|
ef5d335e09 | ||
|
|
25c3060fef | ||
|
|
ce9f0b38a4 | ||
|
|
35f7cbf772 | ||
|
|
def7758a23 | ||
|
|
58e5b4ad25 | ||
|
|
578413859c | ||
|
|
0db564d261 | ||
|
|
427b7ea104 | ||
|
|
fa8aa49376 | ||
|
|
3195eb16b2 | ||
|
|
7bf6878b4b | ||
|
|
a891b49c67 | ||
|
|
eed280d169 | ||
|
|
0bc1a115ff | ||
|
|
334bcfa5ef | ||
|
|
106dea4559 | ||
|
|
3ffdcf8114 | ||
|
|
4021a7eb28 | ||
|
|
0690fda0f1 | ||
|
|
d0cc48c6d3 | ||
|
|
d66e3c949e | ||
|
|
7e2e10f02c | ||
|
|
aebec5378c | ||
|
|
0c65a386b5 | ||
|
|
22ca691e75 | ||
|
|
fc6ff69752 | ||
|
|
079e251aca | ||
|
|
67e2c1b563 | ||
|
|
29f5430881 | ||
|
|
b6bd268be2 | ||
|
|
209ee25c32 | ||
|
|
101f285bcd | ||
|
|
566b85b3d6 | ||
|
|
af6beb1d7c | ||
|
|
7d22fe804d | ||
|
|
ce19c13059 | ||
|
|
286dc6322b | ||
|
|
c9346cd40d | ||
|
|
9cfb7ac340 | ||
|
|
3a0e9aab4f | ||
|
|
43caa1ef29 | ||
|
|
1c5683ec78 | ||
|
|
9bee155d59 | ||
|
|
f34b05f4de | ||
|
|
97ce25f4ce | ||
|
|
3b6cd22e32 | ||
|
|
c9c35780d2 | ||
|
|
17f401f374 | ||
|
|
c6c54b3282 | ||
|
|
91455b6860 | ||
|
|
9e14c14a26 | ||
|
|
f16f243c22 | ||
|
|
fe601308e7 | ||
|
|
c507880d8f | ||
|
|
3f8328bbf8 | ||
|
|
e41f6a71b7 | ||
|
|
51f1be7f5b | ||
|
|
c10a5f9ef6 | ||
|
|
3c141de695 | ||
|
|
db263b696c | ||
|
|
f57b855d74 | ||
|
|
da2b9455f2 | ||
|
|
86525d8583 | ||
|
|
c41e52f57a | ||
|
|
55772a0d07 | ||
|
|
965a9e89ac | ||
|
|
51ee06429b | ||
|
|
cb622488c0 | ||
|
|
32f971fec6 | ||
|
|
ca85d09f02 | ||
|
|
8dea76baa4 | ||
|
|
299fbe04c4 | ||
|
|
57fc1df7d7 | ||
|
|
8d266d3941 | ||
|
|
a865b4da1c | ||
|
|
e59f5f3b01 | ||
|
|
8729688feb | ||
|
|
c8b06e7de1 | ||
|
|
eaba76f9e6 | ||
|
|
cb702cc238 | ||
|
|
f1f798bb85 | ||
|
|
c3fd52c177 | ||
|
|
b69b4a0a4a | ||
|
|
50d6072a73 | ||
|
|
d24cd50e61 | ||
|
|
85bff20ae5 | ||
|
|
737fab5471 | ||
|
|
e6592e93a9 | ||
|
|
5a6c4e8ae0 | ||
|
|
9f5875158c | ||
|
|
c3dc33c861 | ||
|
|
7420f47658 | ||
|
|
6be8f2124c | ||
|
|
edfed06001 | ||
|
|
1c646dba91 | ||
|
|
6781068058 | ||
|
|
cfe57c1dfe | ||
|
|
c34d09a971 | ||
|
|
ebd90c4742 | ||
|
|
ba52d34828 | ||
|
|
2f869b3cfc | ||
|
|
ffa21c27a7 | ||
|
|
1b6312afb3 | ||
|
|
bf32dc2e72 | ||
|
|
a15d65f7a2 | ||
|
|
2de8488855 | ||
|
|
129aa4bfaa | ||
|
|
b1d70db63b | ||
|
|
f03c3aafe4 | ||
|
|
51a9f106d1 | ||
|
|
bfc048e3fe | ||
|
|
83418644f7 | ||
|
|
dbc9dd5bfc | ||
|
|
5c480cf883 | ||
|
|
45ab15d4b5 | ||
|
|
adc64e7866 | ||
|
|
4d4a1cfe82 | ||
|
|
f2c7da3705 | ||
|
|
3ab0a82cd3 | ||
|
|
a46d772147 | ||
|
|
f3c50318e8 | ||
|
|
e7aa924c0e | ||
|
|
5266f04970 | ||
|
|
db957cf191 | ||
|
|
8ac514363d | ||
|
|
c2ea68cca4 | ||
|
|
3d86881ce7 | ||
|
|
697d1470f4 | ||
|
|
0b5f8f4051 | ||
|
|
0fed78fbcc | ||
|
|
8c38ef726b | ||
|
|
2399d90334 | ||
|
|
6367d68d1e | ||
|
|
155a84c8a3 | ||
|
|
10558c9eff | ||
|
|
dd30d811e6 | ||
|
|
293d8e4ddb | ||
|
|
77875c9133 | ||
|
|
647b47567e | ||
|
|
b0a1ad3b06 | ||
|
|
1d141bf2e8 | ||
|
|
0d0e279ae2 | ||
|
|
5dc0cee28a | ||
|
|
c15947da56 | ||
|
|
9bc04244e7 | ||
|
|
38c7a27010 | ||
|
|
58741d2791 | ||
|
|
8426470506 | ||
|
|
ccc3280b1a | ||
|
|
2847075705 | ||
|
|
3108ca0549 | ||
|
|
3b849ff497 | ||
|
|
66776b6a85 | ||
|
|
c8c241b50d | ||
|
|
44cb588371 | ||
|
|
6f91b8f8d1 | ||
|
|
3d93379132 | ||
|
|
84fd7d0126 | ||
|
|
7f52287aae | ||
|
|
98b8986868 | ||
|
|
250f2842ee | ||
|
|
9eca1a3a0c | ||
|
|
24b7a03224 | ||
|
|
9007097d24 | ||
|
|
bc445ec6a2 | ||
|
|
4fa0ae521e | ||
|
|
7bdf5fa8b8 | ||
|
|
65b0b976d9 | ||
|
|
a0d275feec | ||
|
|
ece3a8d7be | ||
|
|
463acf51b5 | ||
|
|
1cd16fab87 | ||
|
|
add55c4f33 | ||
|
|
51a9c0ff59 | ||
|
|
6e8a5f0f4e | ||
|
|
8a33702f26 | ||
|
|
a072d49802 | ||
|
|
a0aeeb8e07 | ||
|
|
383b225690 | ||
|
|
ace2247800 | ||
|
|
6a6fed5dce | ||
|
|
1f8aece8cd | ||
|
|
6c6f8cd4f9 | ||
|
|
fb1311e013 | ||
|
|
ce31acf030 | ||
|
|
31ad5ac63b | ||
|
|
1ede0bdec4 | ||
|
|
aef32ead2c | ||
|
|
5b43ec7f73 | ||
|
|
1e9ff88a00 | ||
|
|
bb9bb5f5c5 | ||
|
|
c533abd8b6 | ||
|
|
bb9bc764bc | ||
|
|
b4b53a6cb7 | ||
|
|
9c0204906c | ||
|
|
4670b373c1 | ||
|
|
f03b5883bd | ||
|
|
f8b2fe4dd5 | ||
|
|
be4a0c9c2b | ||
|
|
f37d52d8e9 | ||
|
|
177cdaf550 | ||
|
|
1573a443b7 | ||
|
|
911c0466c0 | ||
|
|
b6a95f9970 |
@@ -7,6 +7,8 @@ ignorePaths:
|
||||
- cmake/**
|
||||
- LICENSE.md
|
||||
- .clang-tidy
|
||||
- src/test/app/wasm_fixtures/**/*.wat
|
||||
- src/test/app/wasm_fixtures/*.c
|
||||
language: en
|
||||
allowCompoundWords: true # TODO (#6334)
|
||||
ignoreRandomStrings: true
|
||||
@@ -67,6 +69,7 @@ words:
|
||||
- Btrfs
|
||||
- Buildx
|
||||
- canonicality
|
||||
- cdylib
|
||||
- canonicalised
|
||||
- changespq
|
||||
- checkme
|
||||
@@ -111,7 +114,7 @@ words:
|
||||
- doxyfile
|
||||
- dxrpl
|
||||
- elgamal
|
||||
- enabled
|
||||
- emittance
|
||||
- enablerepo
|
||||
- endmacro
|
||||
- envrc
|
||||
@@ -296,7 +299,9 @@ words:
|
||||
- statsd
|
||||
- STATSDCOLLECTOR
|
||||
- stissue
|
||||
- stjson
|
||||
- stnum
|
||||
- stnumber
|
||||
- stobj
|
||||
- stobject
|
||||
- stpath
|
||||
@@ -363,6 +368,7 @@ words:
|
||||
- wthread
|
||||
- xbridge
|
||||
- xchain
|
||||
- xfloat
|
||||
- ximinez
|
||||
- XMACRO
|
||||
- xrpkuwait
|
||||
|
||||
2
.github/CODEOWNERS
vendored
Normal file
2
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Allow anyone to review any change by default.
|
||||
*
|
||||
@@ -19,6 +19,7 @@ libxrpl.ledger > xrpl.json
|
||||
libxrpl.ledger > xrpl.ledger
|
||||
libxrpl.ledger > xrpl.nodestore
|
||||
libxrpl.ledger > xrpl.protocol
|
||||
libxrpl.ledger > xrpl.server
|
||||
libxrpl.ledger > xrpl.shamap
|
||||
libxrpl.net > xrpl.basics
|
||||
libxrpl.net > xrpl.net
|
||||
@@ -206,6 +207,7 @@ xrpl.core > xrpl.json
|
||||
xrpl.core > xrpl.protocol
|
||||
xrpl.json > xrpl.basics
|
||||
xrpl.ledger > xrpl.basics
|
||||
xrpl.ledger > xrpl.core
|
||||
xrpl.ledger > xrpl.json
|
||||
xrpl.ledger > xrpl.nodestore
|
||||
xrpl.ledger > xrpl.protocol
|
||||
|
||||
@@ -114,6 +114,7 @@ find_package(OpenSSL REQUIRED)
|
||||
find_package(secp256k1 REQUIRED)
|
||||
find_package(SOCI REQUIRED)
|
||||
find_package(SQLite3 REQUIRED)
|
||||
find_package(wasmi REQUIRED)
|
||||
find_package(xxHash REQUIRED)
|
||||
|
||||
target_link_libraries(
|
||||
|
||||
@@ -1348,6 +1348,39 @@
|
||||
# Example:
|
||||
# owner_reserve = 200000 # 0.2 XRP
|
||||
#
|
||||
# gas_limit = <gas>
|
||||
#
|
||||
# The gas limit is the maximum amount of gas that can be
|
||||
# consumed by a single transaction. The gas limit is used to prevent
|
||||
# transactions from consuming too many resources.
|
||||
#
|
||||
# If this parameter is unspecified, xrpld will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# gas_limit = 1000000 # 1 million gas
|
||||
#
|
||||
# bytecode_size_limit = <bytes>
|
||||
#
|
||||
# The bytecode size limit is the maximum size of a WASM extension in
|
||||
# bytes. The size limit is used to prevent extensions from consuming
|
||||
# too many resources.
|
||||
#
|
||||
# If this parameter is unspecified, xrpld will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# bytecode_size_limit = 100000 # 100 kb
|
||||
#
|
||||
# gas_price = <micro-drops>
|
||||
#
|
||||
# The gas price is the conversion between WASM gas and its price in drops.
|
||||
#
|
||||
# If this parameter is unspecified, xrpld will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# gas_price = 1000000 # 1 drop per gas
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 9. Misc Settings
|
||||
|
||||
@@ -67,6 +67,7 @@ target_link_libraries(
|
||||
Xrpl::opts
|
||||
Xrpl::syslibs
|
||||
secp256k1::secp256k1
|
||||
wasmi::wasmi
|
||||
xrpl.libpb
|
||||
xxHash::xxhash
|
||||
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
|
||||
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688",
|
||||
"wasmi/1.0.9#1fecdab9b90c96698eb35ea99ca4f5cb%1782307153.343419",
|
||||
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447",
|
||||
"soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521",
|
||||
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168",
|
||||
|
||||
@@ -35,6 +35,7 @@ class Xrpl(ConanFile):
|
||||
"nudb/2.0.9",
|
||||
"openssl/3.6.3",
|
||||
"soci/4.0.3",
|
||||
"wasmi/1.0.9",
|
||||
"zlib/1.3.2",
|
||||
]
|
||||
|
||||
@@ -223,6 +224,7 @@ class Xrpl(ConanFile):
|
||||
"soci::soci",
|
||||
"secp256k1::secp256k1",
|
||||
"sqlite3::sqlite",
|
||||
"wasmi::wasmi",
|
||||
"xxhash::xxhash",
|
||||
"zlib::zlib",
|
||||
]
|
||||
|
||||
@@ -304,7 +304,7 @@ concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::u
|
||||
* on-ledger are non-negative. This is due to implementation details of
|
||||
* several operations which use unsigned arithmetic internally. This is
|
||||
* sufficient to represent all valid XRP values (where the absolute value
|
||||
* can not exceed INITIAL_XRP: 10^17), and MPT values (where the absolute
|
||||
* can not exceed kInitialXrp: 10^17), and MPT values (where the absolute
|
||||
* value can not exceed maxMPTokenAmount: 2^63-1).
|
||||
*
|
||||
* ---- Mantissa Range Switching ----
|
||||
@@ -549,8 +549,21 @@ public:
|
||||
setround(RoundingMode inMode);
|
||||
|
||||
/**
|
||||
* Returns which mantissa scale is currently in use for normalization.
|
||||
* Convert an integer to a RoundingMode, validating that it is in range.
|
||||
*
|
||||
* Returns std::nullopt if the value does not correspond to a valid
|
||||
* RoundingMode.
|
||||
*/
|
||||
static std::optional<RoundingMode>
|
||||
checkedRoundingMode(int mode) noexcept
|
||||
{
|
||||
if (mode < static_cast<int>(RoundingMode::ToNearest) ||
|
||||
mode > static_cast<int>(RoundingMode::Upward))
|
||||
return std::nullopt;
|
||||
return static_cast<RoundingMode>(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* If you think you need to call this outside of unit tests, no you don't.
|
||||
*/
|
||||
static MantissaRange::MantissaScale
|
||||
|
||||
@@ -94,6 +94,7 @@ struct Keys
|
||||
static constexpr auto kBbtOptions = "bbt_options";
|
||||
static constexpr auto kBgThreads = "bg_threads";
|
||||
static constexpr auto kBlockSize = "block_size";
|
||||
static constexpr auto kBytecodeSizeLimit = "bytecode_size_limit";
|
||||
static constexpr auto kCacheAge = "cache_age";
|
||||
static constexpr auto kCacheMb = "cache_mb";
|
||||
static constexpr auto kCacheSize = "cache_size";
|
||||
@@ -108,6 +109,8 @@ struct Keys
|
||||
static constexpr auto kFileSizeMult = "file_size_mult";
|
||||
static constexpr auto kFilterBits = "filter_bits";
|
||||
static constexpr auto kFilterFull = "filter_full";
|
||||
static constexpr auto kGasLimit = "gas_limit";
|
||||
static constexpr auto kGasPrice = "gas_price";
|
||||
static constexpr auto kHardSet = "hard_set";
|
||||
static constexpr auto kHighThreads = "high_threads";
|
||||
static constexpr auto kHoldTime = "hold_time";
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/protocol/Fees.h>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
@@ -246,6 +247,9 @@ public:
|
||||
virtual DatabaseCon&
|
||||
getWalletDB() = 0;
|
||||
|
||||
[[nodiscard]] virtual Fees
|
||||
getFees() const = 0;
|
||||
|
||||
// Temporary: Get the underlying Application for functions that haven't
|
||||
// been migrated yet. This should be removed once all code is migrated.
|
||||
virtual Application&
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <xrpl/protocol/TxMeta.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
@@ -68,6 +69,18 @@ public:
|
||||
deliver_ = amount;
|
||||
}
|
||||
|
||||
void
|
||||
setGasUsed(std::optional<std::uint32_t> const gasUsed)
|
||||
{
|
||||
gasUsed_ = gasUsed;
|
||||
}
|
||||
|
||||
void
|
||||
setVMReturnCode(std::int32_t const vmReturnCode)
|
||||
{
|
||||
vmReturnCode_ = vmReturnCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of modified entries
|
||||
*/
|
||||
@@ -88,6 +101,8 @@ public:
|
||||
|
||||
private:
|
||||
std::optional<STAmount> deliver_;
|
||||
std::optional<std::uint32_t> gasUsed_;
|
||||
std::optional<std::int32_t> vmReturnCode_;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
82
include/xrpl/ledger/OpenViewSandbox.h
Normal file
82
include/xrpl/ledger/OpenViewSandbox.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class OpenViewSandbox
|
||||
{
|
||||
private:
|
||||
OpenView& parent_;
|
||||
std::unique_ptr<OpenView> sandbox_;
|
||||
|
||||
public:
|
||||
using key_type = ReadView::key_type;
|
||||
|
||||
OpenViewSandbox(OpenView& parent)
|
||||
: parent_(parent), sandbox_(std::make_unique<OpenView>(kBatchView, parent))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
rawErase(std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
sandbox_->rawErase(sle);
|
||||
}
|
||||
|
||||
void
|
||||
rawInsert(std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
sandbox_->rawInsert(sle);
|
||||
}
|
||||
|
||||
void
|
||||
rawReplace(std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
sandbox_->rawReplace(sle);
|
||||
}
|
||||
|
||||
void
|
||||
rawDestroyXRP(XRPAmount const& fee)
|
||||
{
|
||||
sandbox_->rawDestroyXRP(fee);
|
||||
}
|
||||
|
||||
void
|
||||
rawTxInsert(
|
||||
key_type const& key,
|
||||
std::shared_ptr<Serializer const> const& txn,
|
||||
std::shared_ptr<Serializer const> const& metaData)
|
||||
{
|
||||
sandbox_->rawTxInsert(key, txn, metaData);
|
||||
}
|
||||
|
||||
void
|
||||
commit()
|
||||
{
|
||||
sandbox_->apply(parent_);
|
||||
sandbox_ = std::make_unique<OpenView>(kBatchView, parent_);
|
||||
}
|
||||
|
||||
void
|
||||
discard()
|
||||
{
|
||||
sandbox_ = std::make_unique<OpenView>(kBatchView, parent_);
|
||||
}
|
||||
|
||||
OpenView const&
|
||||
view() const
|
||||
{
|
||||
return *sandbox_;
|
||||
}
|
||||
|
||||
OpenView&
|
||||
view()
|
||||
{
|
||||
return *sandbox_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -5,6 +5,10 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/OfferHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
@@ -225,6 +229,27 @@ doWithdraw(
|
||||
STAmount const& amount,
|
||||
beast::Journal j);
|
||||
|
||||
enum class SendIssuerHandling { ihSENDER_NOT_ALLOWED, ihRECEIVER_NOT_ALLOWED, ihIGNORE };
|
||||
enum class SendEscrowHandling { ehIGNORE, ehCHECK };
|
||||
enum class SendAuthHandling { ahCHECK_SENDER, ahCHECK_RECEIVER, ahBOTH, ahNEITHER };
|
||||
enum class SendFreezeHandling { fhCHECK_SENDER, fhCHECK_RECEIVER, fhBOTH, fhNEITHER };
|
||||
enum class SendTransferHandling { thIGNORE, thCHECK };
|
||||
enum class SendBalanceHandling { bhIGNORE, bhCHECK };
|
||||
|
||||
TER
|
||||
canTransferFT(
|
||||
ReadView const& view,
|
||||
AccountID const& sender,
|
||||
AccountID const& receiver,
|
||||
STAmount const& amount,
|
||||
beast::Journal j,
|
||||
SendIssuerHandling issuerHandling,
|
||||
SendEscrowHandling escrowHandling,
|
||||
SendAuthHandling authHandling,
|
||||
SendFreezeHandling freezeHandling,
|
||||
SendTransferHandling transferHandling,
|
||||
SendBalanceHandling balanceHandling);
|
||||
|
||||
/**
|
||||
* Deleter function prototype. Returns the status of the entry deletion
|
||||
* (if should not be skipped) and if the entry should be skipped. The status
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
@@ -62,6 +63,8 @@ public:
|
||||
TER ter,
|
||||
std::optional<STAmount> const& deliver,
|
||||
std::optional<uint256 const> const& parentBatchId,
|
||||
std::optional<std::uint32_t> const& gasUsed,
|
||||
std::optional<std::int32_t> const& vmReturnCode,
|
||||
bool isDryRun,
|
||||
beast::Journal j);
|
||||
|
||||
|
||||
102
include/xrpl/ledger/helpers/ContractUtils.h
Normal file
102
include/xrpl/ledger/helpers/ContractUtils.h
Normal file
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/STData.h>
|
||||
#include <xrpl/protocol/STJson.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class ContractDataMap : public std::map<xrpl::AccountID, std::pair<bool, STJson>>
|
||||
{
|
||||
public:
|
||||
uint32_t modifiedCount = 0;
|
||||
};
|
||||
|
||||
class ContractEventMap : public std::map<std::string, STJson>
|
||||
{
|
||||
};
|
||||
|
||||
namespace contract {
|
||||
|
||||
/** The maximum number of data modifications in a single function. */
|
||||
int64_t constexpr maxDataModifications = 1000;
|
||||
|
||||
/** The maximum number of bytes the data can occupy. */
|
||||
int64_t constexpr maxContractDataSize = 1024;
|
||||
|
||||
/** The multiplier for contract data size calculations. */
|
||||
int64_t constexpr dataByteMultiplier = 512;
|
||||
|
||||
/** The cost multiplier of creating a contract in bytes. */
|
||||
int64_t constexpr createByteMultiplier = 500ULL;
|
||||
|
||||
/** The value to return when the fee calculation failed. */
|
||||
int64_t constexpr feeCalculationFailed = 0x7FFFFFFFFFFFFFFFLL;
|
||||
|
||||
/** The maximum number of contract parameters that can be in a transaction. */
|
||||
std::size_t constexpr maxContractParams = 8;
|
||||
|
||||
/** The maximum number of contract functions that can be in a transaction. */
|
||||
std::size_t constexpr maxContractFunctions = 32;
|
||||
|
||||
int64_t
|
||||
contractCreateFee(uint64_t byteCount);
|
||||
|
||||
NotTEC
|
||||
preflightFunctions(STTx const& tx, beast::Journal j);
|
||||
|
||||
NotTEC
|
||||
preflightInstanceParameters(STTx const& tx, beast::Journal j);
|
||||
|
||||
bool
|
||||
validateParameterMapping(STArray const& params, STArray const& values, beast::Journal j);
|
||||
|
||||
NotTEC
|
||||
preflightInstanceParameterValues(STTx const& tx, beast::Journal j);
|
||||
|
||||
NotTEC
|
||||
preflightFlagParameters(STArray const& parameters, beast::Journal j);
|
||||
|
||||
bool
|
||||
isValidParameterFlag(std::uint32_t flags);
|
||||
|
||||
TER
|
||||
preclaimFlagParameters(
|
||||
ReadView const& view,
|
||||
AccountID const& sourceAccount,
|
||||
AccountID const& contractAccount,
|
||||
STArray const& parameters,
|
||||
beast::Journal j);
|
||||
|
||||
TER
|
||||
doApplyFlagParameters(
|
||||
ApplyView& view,
|
||||
STTx const& tx,
|
||||
AccountID const& sourceAccount,
|
||||
AccountID const& contractAccount,
|
||||
STArray const& parameters,
|
||||
XRPAmount const& priorBalance,
|
||||
beast::Journal j);
|
||||
|
||||
TER
|
||||
finalizeContractData(
|
||||
ServiceRegistry& registry,
|
||||
ApplyView& view,
|
||||
AccountID const& contractAccount,
|
||||
ContractDataMap const& dataMap,
|
||||
ContractEventMap const& eventMap,
|
||||
uint256 const& txnID);
|
||||
|
||||
} // namespace contract
|
||||
} // namespace xrpl
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <ValidIssueType T>
|
||||
@@ -272,4 +274,18 @@ escrowUnlockApplyHelper<MPTIssue>(
|
||||
journal);
|
||||
}
|
||||
|
||||
// calculateAdditionalReserve computes the owner count impact of an Escrow.
|
||||
// An escrow without a FinishFunction costs 1 reserve. With a FinishFunction,
|
||||
// each additional 500 bytes beyond the first 500 adds another reserve slot.
|
||||
template <class T>
|
||||
static int32_t
|
||||
calculateAdditionalReserve(T const& finishFunction)
|
||||
{
|
||||
if (!finishFunction)
|
||||
return 1;
|
||||
// First 500 bytes included in the normal reserve
|
||||
// Each additional 500 bytes requires an additional reserve
|
||||
return 1 + (finishFunction->size() / 500);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/protocol/nft.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -161,4 +162,12 @@ checkTrustlineDeepFrozen(
|
||||
beast::Journal const j,
|
||||
Issue const& issue);
|
||||
|
||||
TER
|
||||
transferNFToken(
|
||||
ApplyView& view,
|
||||
AccountID const& buyer,
|
||||
AccountID const& seller,
|
||||
uint256 const& nftokenID,
|
||||
beast::Journal j);
|
||||
|
||||
} // namespace xrpl::nft
|
||||
|
||||
@@ -47,7 +47,7 @@ ammLPTIssue(Asset const& asset1, Asset const& asset2, AccountID const& ammAccoun
|
||||
|
||||
/**
|
||||
* Validate the amount.
|
||||
* If validZero is false and amount is beast::zero then invalid amount.
|
||||
* If validZero is false and amount is beast::kZero then invalid amount.
|
||||
* Return error code if invalid amount.
|
||||
* If pair then validate amount's issue matches one of the pair's issue.
|
||||
*/
|
||||
|
||||
78
include/xrpl/protocol/Emitable.h
Normal file
78
include/xrpl/protocol/Emitable.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/Rules.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace xrpl {
|
||||
/**
|
||||
* We have both transaction type emitables and granular type emitables.
|
||||
* Since we will reuse the TransactionFormats to parse the Transaction
|
||||
* Emitables, only the GranularEmitableType is defined here. To prevent
|
||||
* conflicts with TxType, the GranularEmitableType is always set to a value
|
||||
* greater than the maximum value of uint16.
|
||||
*/
|
||||
enum GranularEmitableType : std::uint32_t {
|
||||
#pragma push_macro("EMITABLE")
|
||||
#undef EMITABLE
|
||||
|
||||
#define EMITABLE(type, txType, value) type = value,
|
||||
|
||||
#include <xrpl/protocol/detail/emitable.macro>
|
||||
|
||||
#undef EMITABLE
|
||||
#pragma pop_macro("EMITABLE")
|
||||
};
|
||||
|
||||
enum Emittance { emitable, notEmitable };
|
||||
|
||||
class Emitable
|
||||
{
|
||||
private:
|
||||
Emitable();
|
||||
|
||||
std::unordered_map<std::uint16_t, Emittance> emitableTx_;
|
||||
|
||||
std::unordered_map<std::string, GranularEmitableType> granularEmitableMap_;
|
||||
|
||||
std::unordered_map<GranularEmitableType, std::string> granularNameMap_;
|
||||
|
||||
std::unordered_map<GranularEmitableType, TxType> granularTxTypeMap_;
|
||||
|
||||
public:
|
||||
static Emitable const&
|
||||
getInstance();
|
||||
|
||||
Emitable(Emitable const&) = delete;
|
||||
Emitable&
|
||||
operator=(Emitable const&) = delete;
|
||||
|
||||
std::optional<std::string>
|
||||
getEmitableName(std::uint32_t const value) const;
|
||||
|
||||
std::optional<std::uint32_t>
|
||||
getGranularValue(std::string const& name) const;
|
||||
|
||||
std::optional<std::string>
|
||||
getGranularName(GranularEmitableType const& value) const;
|
||||
|
||||
std::optional<TxType>
|
||||
getGranularTxType(GranularEmitableType const& gpType) const;
|
||||
|
||||
bool
|
||||
isEmitable(std::uint32_t const& emitableValue) const;
|
||||
|
||||
// for tx level emitable, emitable value is equal to tx type plus one
|
||||
uint32_t
|
||||
txToEmitableType(TxType const& type) const;
|
||||
|
||||
// tx type value is emitable value minus one
|
||||
TxType
|
||||
emitableToTxType(uint32_t const& value) const;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -10,6 +10,15 @@ namespace xrpl {
|
||||
// This was the reference fee units used in the old fee calculation.
|
||||
inline constexpr std::uint32_t kFeeUnitsDeprecated = 10;
|
||||
|
||||
// Number of micro-drops in one drop.
|
||||
constexpr std::uint32_t microDropsPerDrop{1'000'000};
|
||||
|
||||
/**
|
||||
* Maximum Feature Extension fee settings.
|
||||
*/
|
||||
inline constexpr std::uint32_t kMaxGasLimit{2'000'000};
|
||||
inline constexpr std::uint32_t kMaxBytecodeSizeLimit{200'000};
|
||||
|
||||
/**
|
||||
* Reflects the fee settings for a particular ledger.
|
||||
*
|
||||
@@ -33,6 +42,21 @@ struct Fees
|
||||
*/
|
||||
XRPAmount increment{0};
|
||||
|
||||
/**
|
||||
* @brief Gas limit for Feature Extensions (instructions).
|
||||
*/
|
||||
std::uint32_t gasLimit{0};
|
||||
|
||||
/**
|
||||
* @brief Bytecode size limit for Feature Extensions (bytes).
|
||||
*/
|
||||
std::uint32_t bytecodeSizeLimit{0};
|
||||
|
||||
/**
|
||||
* @brief Price of WASM gas (micro-drops).
|
||||
*/
|
||||
std::uint32_t gasPrice{0};
|
||||
|
||||
explicit Fees() = default;
|
||||
Fees(Fees const&) = default;
|
||||
Fees&
|
||||
|
||||
@@ -237,6 +237,12 @@ page(Keylet const& root, std::uint64_t const index = 0) noexcept
|
||||
Keylet
|
||||
escrow(AccountID const& src, SeqProxy const& seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
escrow(uint256 const& key) noexcept
|
||||
{
|
||||
return {ltESCROW, key};
|
||||
}
|
||||
|
||||
/**
|
||||
* A PaymentChannel
|
||||
*/
|
||||
@@ -386,6 +392,22 @@ permissionedDomain(AccountID const& account, SeqProxy const& seq) noexcept;
|
||||
|
||||
Keylet
|
||||
permissionedDomain(uint256 const& domainID) noexcept;
|
||||
|
||||
Keylet
|
||||
contractSource(uint256 const& contractHash) noexcept;
|
||||
|
||||
Keylet
|
||||
contract(uint256 const& contractHash, AccountID const& owner, std::uint32_t seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
contract(uint256 const& contractID)
|
||||
{
|
||||
return {ltCONTRACT, contractID};
|
||||
}
|
||||
|
||||
Keylet
|
||||
contractData(AccountID const& owner, AccountID const& contractAccount) noexcept;
|
||||
|
||||
} // namespace keylet
|
||||
|
||||
// Everything below is deprecated and should be removed in favor of keylets:
|
||||
|
||||
@@ -85,15 +85,6 @@ enum LedgerEntryType : std::uint16_t {
|
||||
*/
|
||||
ltNICKNAME [[deprecated("This object type is not supported and should not be used.")]] = 0x006e,
|
||||
|
||||
/**
|
||||
* A legacy, deprecated type.
|
||||
*
|
||||
* @deprecated **This object type is not supported and should not be used.**
|
||||
* Support for this type of object was never implemented.
|
||||
* No objects of this type were ever created.
|
||||
*/
|
||||
ltCONTRACT [[deprecated("This object type is not supported and should not be used.")]] = 0x0063,
|
||||
|
||||
/**
|
||||
* A legacy, deprecated type.
|
||||
*
|
||||
|
||||
@@ -333,6 +333,16 @@ enum class VaultVersion : uint8_t {
|
||||
*/
|
||||
constexpr std::uint8_t kMaxAssetCheckDepth = 5;
|
||||
|
||||
/**
|
||||
* Maximum length of a Data field in Escrow object that can be updated by WASM code.
|
||||
*/
|
||||
constexpr std::size_t kMaxWasmDataLength = 1 * 1024; // 1KB
|
||||
|
||||
/**
|
||||
* Maximum amount of data transfer across hostfunction<->wasm border.
|
||||
*/
|
||||
constexpr std::size_t kWasmTransferLimit = 1 << 20; // 1MB
|
||||
|
||||
/**
|
||||
* A ledger index.
|
||||
*/
|
||||
|
||||
@@ -34,6 +34,9 @@ class STNumber;
|
||||
class STXChainBridge;
|
||||
class STVector256;
|
||||
class STCurrency;
|
||||
class STData;
|
||||
class STDataType;
|
||||
class STJson;
|
||||
|
||||
// NOLINTBEGIN(readability-identifier-naming)
|
||||
#pragma push_macro("XMACRO")
|
||||
@@ -73,6 +76,9 @@ class STCurrency;
|
||||
STYPE(STI_ISSUE, 24) \
|
||||
STYPE(STI_XCHAIN_BRIDGE, 25) \
|
||||
STYPE(STI_CURRENCY, 26) \
|
||||
STYPE(STI_DATA, 27) \
|
||||
STYPE(STI_DATATYPE, 28) \
|
||||
STYPE(STI_JSON, 29) \
|
||||
\
|
||||
/* high-level types */ \
|
||||
/* cannot be serialized inside other types */ \
|
||||
@@ -359,6 +365,9 @@ using SF_NUMBER = TypedField<STNumber>;
|
||||
using SF_VL = TypedField<STBlob>;
|
||||
using SF_VECTOR256 = TypedField<STVector256>;
|
||||
using SF_XCHAIN_BRIDGE = TypedField<STXChainBridge>;
|
||||
using SF_DATA = TypedField<STData>;
|
||||
using SF_DATATYPE = TypedField<STDataType>;
|
||||
using SF_JSON = TypedField<STJson>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
289
include/xrpl/protocol/STData.h
Normal file
289
include/xrpl/protocol/STData.h
Normal file
@@ -0,0 +1,289 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Buffer.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
#include <xrpl/protocol/STBitString.h>
|
||||
#include <xrpl/protocol/STInteger.h>
|
||||
#include <xrpl/protocol/detail/STVar.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class STData final : public STBase
|
||||
{
|
||||
private:
|
||||
using data_type = detail::STVar;
|
||||
std::uint16_t inner_type_;
|
||||
data_type data_;
|
||||
bool default_{true};
|
||||
|
||||
public:
|
||||
using value_type = STData; // Although not directly holding a single value
|
||||
|
||||
STData(SField const& n);
|
||||
STData(SField const& n, unsigned char);
|
||||
STData(SField const& n, std::uint16_t);
|
||||
STData(SField const& n, std::uint32_t);
|
||||
STData(SField const& n, std::uint64_t);
|
||||
STData(SField const& n, uint128 const&);
|
||||
STData(SField const& n, uint160 const&);
|
||||
STData(SField const& n, uint192 const&);
|
||||
STData(SField const& n, uint256 const&);
|
||||
STData(SField const& n, Blob const&);
|
||||
STData(SField const& n, Slice const&);
|
||||
STData(SField const& n, AccountID const&);
|
||||
STData(SField const& n, STAmount const&);
|
||||
STData(SField const& n, STIssue const&);
|
||||
STData(SField const& n, STCurrency const&);
|
||||
STData(SField const& n, STNumber const&);
|
||||
|
||||
STData(SerialIter& sit, SField const& name);
|
||||
|
||||
std::size_t
|
||||
size() const;
|
||||
|
||||
SerializedTypeID
|
||||
getSType() const override;
|
||||
|
||||
std::string
|
||||
getInnerTypeString() const;
|
||||
|
||||
std::string
|
||||
getText() const override;
|
||||
|
||||
json::Value getJson(JsonOptions) const override;
|
||||
|
||||
void
|
||||
add(Serializer& s) const override;
|
||||
|
||||
bool
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
|
||||
SerializedTypeID
|
||||
getInnerSType() const noexcept;
|
||||
|
||||
STBase*
|
||||
makeFieldPresent();
|
||||
|
||||
void
|
||||
setFieldU8(unsigned char);
|
||||
void
|
||||
setFieldU16(std::uint16_t);
|
||||
void
|
||||
setFieldU32(std::uint32_t);
|
||||
void
|
||||
setFieldU64(std::uint64_t);
|
||||
void
|
||||
setFieldH128(uint128 const&);
|
||||
void
|
||||
setFieldH160(uint160 const&);
|
||||
void
|
||||
setFieldH192(uint192 const&);
|
||||
void
|
||||
setFieldH256(uint256 const&);
|
||||
void
|
||||
setFieldVL(Blob const&);
|
||||
void
|
||||
setFieldVL(Slice const&);
|
||||
void
|
||||
setAccountID(AccountID const&);
|
||||
void
|
||||
setFieldAmount(STAmount const&);
|
||||
void
|
||||
setIssue(STIssue const&);
|
||||
void
|
||||
setCurrency(STCurrency const&);
|
||||
void
|
||||
setFieldNumber(STNumber const&);
|
||||
|
||||
unsigned char
|
||||
getFieldU8() const;
|
||||
std::uint16_t
|
||||
getFieldU16() const;
|
||||
std::uint32_t
|
||||
getFieldU32() const;
|
||||
std::uint64_t
|
||||
getFieldU64() const;
|
||||
uint128
|
||||
getFieldH128() const;
|
||||
uint160
|
||||
getFieldH160() const;
|
||||
uint192
|
||||
getFieldH192() const;
|
||||
uint256
|
||||
getFieldH256() const;
|
||||
Blob
|
||||
getFieldVL() const;
|
||||
AccountID
|
||||
getAccountID() const;
|
||||
STAmount const&
|
||||
getFieldAmount() const;
|
||||
STIssue
|
||||
getFieldIssue() const;
|
||||
STCurrency
|
||||
getFieldCurrency() const;
|
||||
STNumber
|
||||
getFieldNumber() const;
|
||||
|
||||
private:
|
||||
STBase*
|
||||
copy(std::size_t n, void* buf) const override;
|
||||
STBase*
|
||||
move(std::size_t n, void* buf) override;
|
||||
|
||||
friend class detail::STVar;
|
||||
|
||||
// Implementation for getting (most) fields that return by value.
|
||||
//
|
||||
// The remove_cv and remove_reference are necessitated by the STBitString
|
||||
// types. Their value() returns by const ref. We return those types
|
||||
// by value.
|
||||
template <
|
||||
typename T,
|
||||
typename V = typename std::remove_cv<
|
||||
typename std::remove_reference<decltype(std::declval<T>().value())>::type>::type>
|
||||
V
|
||||
getFieldByValue() const;
|
||||
|
||||
// Implementations for getting (most) fields that return by const reference.
|
||||
//
|
||||
// If an absent optional field is deserialized we don't have anything
|
||||
// obvious to return. So we insist on having the call provide an
|
||||
// 'empty' value we return in that circumstance.
|
||||
template <typename T, typename V>
|
||||
V const&
|
||||
getFieldByConstRef(V const& empty) const;
|
||||
|
||||
// Implementation for setting most fields with a setValue() method.
|
||||
template <typename T, typename V>
|
||||
void
|
||||
setFieldUsingSetValue(V value);
|
||||
|
||||
// Implementation for setting fields using assignment
|
||||
template <typename T>
|
||||
void
|
||||
setFieldUsingAssignment(T const& value);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Implementation
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline SerializedTypeID
|
||||
STData::getInnerSType() const noexcept
|
||||
{
|
||||
return static_cast<SerializedTypeID>(inner_type_);
|
||||
}
|
||||
|
||||
template <typename T, typename V>
|
||||
V
|
||||
STData::getFieldByValue() const
|
||||
{
|
||||
STBase const* rf = &data_.get();
|
||||
|
||||
// if (!rf)
|
||||
// throwFieldNotFound(getFName());
|
||||
|
||||
SerializedTypeID const id = rf->getSType();
|
||||
|
||||
if (id == STI_NOTPRESENT)
|
||||
Throw<std::runtime_error>("Field not present");
|
||||
|
||||
T const* cf = dynamic_cast<T const*>(rf);
|
||||
|
||||
if (!cf)
|
||||
Throw<std::runtime_error>("Wrong field type");
|
||||
|
||||
return cf->value();
|
||||
}
|
||||
|
||||
// Implementations for getting (most) fields that return by const reference.
|
||||
//
|
||||
// If an absent optional field is deserialized we don't have anything
|
||||
// obvious to return. So we insist on having the call provide an
|
||||
// 'empty' value we return in that circumstance.
|
||||
template <typename T, typename V>
|
||||
V const&
|
||||
STData::getFieldByConstRef(V const& empty) const
|
||||
{
|
||||
STBase const* rf = &data_.get();
|
||||
|
||||
// if (!rf)
|
||||
// throwFieldNotFound(field);
|
||||
|
||||
SerializedTypeID const id = rf->getSType();
|
||||
|
||||
if (id == STI_NOTPRESENT)
|
||||
return empty; // optional field not present
|
||||
|
||||
T const* cf = dynamic_cast<T const*>(rf);
|
||||
|
||||
if (!cf)
|
||||
Throw<std::runtime_error>("Wrong field type");
|
||||
|
||||
return *cf;
|
||||
}
|
||||
|
||||
// Implementation for setting most fields with a setValue() method.
|
||||
template <typename T, typename V>
|
||||
void
|
||||
STData::setFieldUsingSetValue(V value)
|
||||
{
|
||||
static_assert(!std::is_lvalue_reference<V>::value, "");
|
||||
|
||||
STBase* rf = &data_.get();
|
||||
|
||||
// if (!rf)
|
||||
// throwFieldNotFound(field);
|
||||
|
||||
if (rf->getSType() == STI_NOTPRESENT)
|
||||
rf = makeFieldPresent();
|
||||
|
||||
T* cf = dynamic_cast<T*>(rf);
|
||||
|
||||
if (!cf)
|
||||
Throw<std::runtime_error>("Wrong field type");
|
||||
|
||||
cf->setValue(std::move(value));
|
||||
}
|
||||
|
||||
// Implementation for setting fields using assignment
|
||||
template <typename T>
|
||||
void
|
||||
STData::setFieldUsingAssignment(T const& value)
|
||||
{
|
||||
STBase* rf = &data_.get();
|
||||
|
||||
// if (!rf)
|
||||
// throwFieldNotFound(field);
|
||||
|
||||
// if (rf->getSType() == STI_NOTPRESENT)
|
||||
// rf = makeFieldPresent(field);
|
||||
|
||||
T* cf = dynamic_cast<T*>(rf);
|
||||
|
||||
if (!cf)
|
||||
Throw<std::runtime_error>("Wrong field type");
|
||||
|
||||
(*cf) = value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Creation
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
STData
|
||||
dataFromJson(SField const& field, json::Value const& value);
|
||||
|
||||
} // namespace xrpl
|
||||
87
include/xrpl/protocol/STDataType.h
Normal file
87
include/xrpl/protocol/STDataType.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Buffer.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
#include <xrpl/protocol/STBitString.h>
|
||||
#include <xrpl/protocol/STInteger.h>
|
||||
#include <xrpl/protocol/detail/STVar.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class STDataType final : public STBase
|
||||
{
|
||||
private:
|
||||
std::uint16_t inner_type_;
|
||||
bool default_{true};
|
||||
|
||||
public:
|
||||
using value_type = STDataType; // Although not directly holding a single value
|
||||
|
||||
STDataType(SField const& n);
|
||||
STDataType(SField const& n, SerializedTypeID);
|
||||
|
||||
STDataType(SerialIter& sit, SField const& name);
|
||||
|
||||
SerializedTypeID
|
||||
getSType() const override;
|
||||
|
||||
std::string
|
||||
getInnerTypeString() const;
|
||||
|
||||
std::string
|
||||
getText() const override;
|
||||
|
||||
json::Value getJson(JsonOptions) const override;
|
||||
|
||||
void
|
||||
add(Serializer& s) const override;
|
||||
|
||||
bool
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
|
||||
void setInnerSType(SerializedTypeID);
|
||||
|
||||
SerializedTypeID
|
||||
getInnerSType() const noexcept;
|
||||
|
||||
STBase*
|
||||
makeFieldPresent();
|
||||
|
||||
STBase*
|
||||
copy(std::size_t n, void* buf) const override;
|
||||
STBase*
|
||||
move(std::size_t n, void* buf) override;
|
||||
|
||||
friend class detail::STVar;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Implementation
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline SerializedTypeID
|
||||
STDataType::getInnerSType() const noexcept
|
||||
{
|
||||
return static_cast<SerializedTypeID>(inner_type_);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Creation
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
STDataType
|
||||
dataTypeFromJson(SField const& field, json::Value const& value);
|
||||
|
||||
} // namespace xrpl
|
||||
193
include/xrpl/protocol/STJson.h
Normal file
193
include/xrpl/protocol/STJson.h
Normal file
@@ -0,0 +1,193 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* STJson: Serialized Type for JSON-like structures (objects or arrays).
|
||||
*
|
||||
* Supports two modes:
|
||||
* - Object: Key-value pairs where keys are VL-encoded strings
|
||||
* - Array: Ordered list of values
|
||||
*
|
||||
* Values are [SType marker][VL-encoded SType serialization].
|
||||
* Values can be any SType, including nested STJson.
|
||||
*
|
||||
* Serialization format: [type_byte][VL_length][data...]
|
||||
* - type_byte: 0x00 = Object, 0x01 = Array
|
||||
*/
|
||||
class STJson : public STBase
|
||||
{
|
||||
public:
|
||||
enum class JsonType : uint8_t { Object = 0x00, Array = 0x01 };
|
||||
|
||||
using value_type = STJson;
|
||||
value_type
|
||||
value() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
using Key = std::string;
|
||||
using Value = std::shared_ptr<STBase>;
|
||||
using Map = std::map<Key, Value>;
|
||||
using Array = std::vector<Value>;
|
||||
|
||||
STJson() = default;
|
||||
|
||||
explicit STJson(Map&& map);
|
||||
explicit STJson(Array&& array);
|
||||
explicit STJson(SField const& name);
|
||||
explicit STJson(SerialIter& sit, SField const& name);
|
||||
|
||||
SerializedTypeID
|
||||
getSType() const override;
|
||||
|
||||
// Type checking
|
||||
bool
|
||||
isArray() const;
|
||||
|
||||
bool
|
||||
isObject() const;
|
||||
|
||||
JsonType
|
||||
getType() const;
|
||||
|
||||
// Depth checking (0 = no nesting, 1 = one level of nesting)
|
||||
int
|
||||
getDepth() const;
|
||||
|
||||
// Parse from binary blob
|
||||
static std::shared_ptr<STJson>
|
||||
fromBlob(void const* data, std::size_t size);
|
||||
|
||||
// Parse from SerialIter
|
||||
static std::shared_ptr<STJson>
|
||||
fromSerialIter(SerialIter& sit);
|
||||
|
||||
// Serialize to binary
|
||||
void
|
||||
add(Serializer& s) const override;
|
||||
|
||||
// JSON representation
|
||||
json::Value
|
||||
getJson(JsonOptions options) const override;
|
||||
|
||||
bool
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
|
||||
// Blob representation
|
||||
Blob
|
||||
toBlob() const;
|
||||
|
||||
// STJson size
|
||||
std::size_t
|
||||
size() const;
|
||||
|
||||
// Object accessors (only valid when isObject() == true)
|
||||
Map const&
|
||||
getMap() const;
|
||||
|
||||
void
|
||||
setObjectField(Key const& key, Value const& value);
|
||||
|
||||
std::optional<STJson::Value>
|
||||
getObjectField(Key const& key) const;
|
||||
|
||||
void
|
||||
setNestedObjectField(Key const& key, Key const& nestedKey, Value const& value);
|
||||
|
||||
std::optional<Value>
|
||||
getNestedObjectField(Key const& key, Key const& nestedKey) const;
|
||||
|
||||
// Array accessors (only valid when isArray() == true)
|
||||
Array const&
|
||||
getArray() const;
|
||||
|
||||
void
|
||||
pushArrayElement(Value const& value);
|
||||
|
||||
std::optional<Value>
|
||||
getArrayElement(size_t index) const;
|
||||
|
||||
void
|
||||
setArrayElement(size_t index, Value const& value);
|
||||
|
||||
void
|
||||
setArrayElementField(size_t index, Key const& key, Value const& value);
|
||||
|
||||
std::optional<Value>
|
||||
getArrayElementField(size_t index, Key const& key) const;
|
||||
|
||||
size_t
|
||||
arraySize() const;
|
||||
|
||||
// Nested array accessors (for arrays stored in object fields)
|
||||
void
|
||||
setNestedArrayElement(Key const& key, size_t index, Value const& value);
|
||||
|
||||
void
|
||||
setNestedArrayElementField(
|
||||
Key const& key,
|
||||
size_t index,
|
||||
Key const& nestedKey,
|
||||
Value const& value);
|
||||
|
||||
std::optional<Value>
|
||||
getNestedArrayElement(Key const& key, size_t index) const;
|
||||
|
||||
std::optional<Value>
|
||||
getNestedArrayElementField(Key const& key, size_t index, Key const& nestedKey) const;
|
||||
|
||||
// Factory for SType value from blob (with SType marker)
|
||||
static Value
|
||||
makeValueFromVLWithType(SerialIter& sit);
|
||||
|
||||
void
|
||||
setValue(STJson const& v);
|
||||
|
||||
private:
|
||||
std::variant<Map, Array> data_{Map{}};
|
||||
bool default_{false};
|
||||
|
||||
// Helper: validate nesting depth (max 1 level)
|
||||
void
|
||||
validateDepth(Value const& value, int currentDepth) const;
|
||||
|
||||
// Helper: parse a single key-value pair from SerialIter
|
||||
static std::pair<Key, Value>
|
||||
parsePair(SerialIter& sit);
|
||||
|
||||
// Helper: parse array elements from SerialIter
|
||||
static Array
|
||||
parseArray(SerialIter& sit, int length);
|
||||
|
||||
// Helper: encode a key as VL
|
||||
static void
|
||||
addVLKey(Serializer& s, std::string const& str);
|
||||
|
||||
// Helper: encode a value as [SType marker][VL]
|
||||
static void
|
||||
addVLValue(Serializer& s, std::shared_ptr<STBase> const& value);
|
||||
|
||||
STBase*
|
||||
copy(std::size_t n, void* buf) const override;
|
||||
STBase*
|
||||
move(std::size_t n, void* buf) override;
|
||||
|
||||
friend class detail::STVar;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <xrpl/protocol/STBitString.h>
|
||||
#include <xrpl/protocol/STCurrency.h>
|
||||
#include <xrpl/protocol/STIssue.h>
|
||||
#include <xrpl/protocol/STJson.h>
|
||||
#include <xrpl/protocol/STPathSet.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
@@ -232,6 +233,10 @@ public:
|
||||
getFieldI32(SField const& field) const;
|
||||
[[nodiscard]] AccountID
|
||||
getAccountID(SField const& field) const;
|
||||
STData
|
||||
getFieldData(SField const& field) const;
|
||||
STDataType
|
||||
getFieldDataType(SField const& field) const;
|
||||
|
||||
[[nodiscard]] Blob
|
||||
getFieldVL(SField const& field) const;
|
||||
@@ -250,6 +255,8 @@ public:
|
||||
getFieldCurrency(SField const& field) const;
|
||||
[[nodiscard]] STNumber const&
|
||||
getFieldNumber(SField const& field) const;
|
||||
STJson const&
|
||||
getFieldJson(SField const& field) const;
|
||||
|
||||
/**
|
||||
* Get the value of a field.
|
||||
@@ -363,6 +370,9 @@ public:
|
||||
void
|
||||
set(STBase&& v);
|
||||
|
||||
void
|
||||
addFieldFromSlice(SField const& sfield, Slice const& data);
|
||||
|
||||
void
|
||||
setFieldU8(SField const& field, unsigned char);
|
||||
void
|
||||
@@ -403,6 +413,8 @@ public:
|
||||
setFieldArray(SField const& field, STArray const& v);
|
||||
void
|
||||
setFieldObject(SField const& field, STObject const& v);
|
||||
void
|
||||
setFieldJson(SField const& field, STJson const& v);
|
||||
|
||||
template <class Tag>
|
||||
void
|
||||
|
||||
@@ -129,8 +129,12 @@ enum TEMcodes : TERUnderlyingType {
|
||||
temARRAY_TOO_LARGE,
|
||||
temBAD_TRANSFER_FEE,
|
||||
temINVALID_INNER_BATCH,
|
||||
|
||||
temBAD_MPT,
|
||||
temBAD_CIPHERTEXT,
|
||||
temBAD_WASM,
|
||||
temINVALID_BYTECODE,
|
||||
temTEMP_DISABLED,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -179,6 +183,8 @@ enum TEFcodes : TERUnderlyingType {
|
||||
tefINVALID_LEDGER_FIX_TYPE,
|
||||
tefNO_DST_PARTIAL,
|
||||
tefBAD_PATH_COUNT,
|
||||
tefNO_BYTECODE,
|
||||
tefBYTECODE_NOT_INCLUDED,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -370,6 +376,9 @@ enum TECcodes : TERUnderlyingType {
|
||||
tecNO_DELEGATE_PERMISSION = 198,
|
||||
tecBAD_PROOF = 199,
|
||||
tecNO_SPONSOR_PERMISSION = 200,
|
||||
tecOUT_OF_GAS = 201,
|
||||
tecBYTECODE_REJECTED = 202,
|
||||
tecINVALID_PARAMETERS = 203,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -238,8 +238,21 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
|
||||
TF_FLAG(tfSponsorshipEnd, 0x00010000) \
|
||||
TF_FLAG(tfSponsorshipCreate, 0x00020000) \
|
||||
TF_FLAG(tfSponsorshipReassign, 0x00040000), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(Contract, \
|
||||
TF_FLAG(tfImmutable, 0x00010000) \
|
||||
TF_FLAG(tfCodeImmutable, 0x00020000) \
|
||||
TF_FLAG(tfABIImmutable, 0x00040000) \
|
||||
TF_FLAG(tfUndeletable, 0x00080000), \
|
||||
MASK_ADJ(0))
|
||||
|
||||
constexpr std::uint32_t tfSendAmount = 0x00010000;
|
||||
constexpr std::uint32_t tfSendNFToken = 0x00020000;
|
||||
constexpr std::uint32_t tfAuthorizeToken = 0x00040000;
|
||||
constexpr std::uint32_t tfContractParameterMask =
|
||||
~(tfSendAmount | tfSendNFToken | tfAuthorizeToken);
|
||||
|
||||
// clang-format on
|
||||
|
||||
// Create all the flag values.
|
||||
|
||||
@@ -95,6 +95,12 @@ public:
|
||||
|
||||
if (obj.isFieldPresent(sfParentBatchID))
|
||||
parentBatchID_ = obj.getFieldH256(sfParentBatchID);
|
||||
|
||||
if (obj.isFieldPresent(sfGasUsed))
|
||||
gasUsed_ = obj.getFieldU32(sfGasUsed);
|
||||
|
||||
if (obj.isFieldPresent(sfVMReturnCode))
|
||||
vmReturnCode_ = obj.getFieldI32(sfVMReturnCode);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<STAmount> const&
|
||||
@@ -115,6 +121,30 @@ public:
|
||||
parentBatchID_ = id;
|
||||
}
|
||||
|
||||
void
|
||||
setGasUsed(std::optional<std::uint32_t> const gasUsed)
|
||||
{
|
||||
gasUsed_ = gasUsed;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::uint32_t> const&
|
||||
getGasUsed() const
|
||||
{
|
||||
return gasUsed_;
|
||||
}
|
||||
|
||||
void
|
||||
setVMReturnCode(std::optional<std::int32_t> const vmReturnCode)
|
||||
{
|
||||
vmReturnCode_ = vmReturnCode;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::int32_t> const&
|
||||
getVMReturnCode() const
|
||||
{
|
||||
return vmReturnCode_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint256 transactionID_;
|
||||
std::uint32_t ledgerSeq_;
|
||||
@@ -123,6 +153,8 @@ private:
|
||||
|
||||
std::optional<STAmount> deliveredAmount_;
|
||||
std::optional<uint256> parentBatchID_;
|
||||
std::optional<std::uint32_t> gasUsed_;
|
||||
std::optional<std::int32_t> vmReturnCode_;
|
||||
|
||||
STArray nodes_;
|
||||
};
|
||||
|
||||
19
include/xrpl/protocol/detail/emitable.macro
Normal file
19
include/xrpl/protocol/detail/emitable.macro
Normal file
@@ -0,0 +1,19 @@
|
||||
#if !defined(EMITABLE)
|
||||
#error "undefined macro: EMITABLE"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* EMITABLE(name, type, txType, value)
|
||||
*
|
||||
* This macro defines a permission:
|
||||
* name: the name of the permission.
|
||||
* type: the GranularPermissionType enum.
|
||||
* txType: the corresponding TxType for this permission.
|
||||
* value: the uint32 numeric value for the enum type.
|
||||
*/
|
||||
|
||||
/** This removes the contract account the ability to set or remove deposit auth. */
|
||||
EMITABLE(AccountDepositAuth, ttACCOUNT_SET, 65537)
|
||||
|
||||
// ** This removes the contract account the ability to set or remove disable master key. */
|
||||
EMITABLE(AccountDisableMaster, ttACCOUNT_SET, 65538)
|
||||
@@ -15,7 +15,9 @@
|
||||
// Add new amendments to the top of this list.
|
||||
// Keep it sorted in reverse chronological order.
|
||||
|
||||
XRPL_FEATURE(SmartContract, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (Cleanup3_4_0, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(SmartEscrow, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(Sponsor, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(BatchV1_1, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(LendingProtocolV1_1, Supported::No, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -153,6 +153,7 @@ LEDGER_ENTRY(ltACCOUNT_ROOT, 0x0061, AccountRoot, account, ({
|
||||
{sfAMMID, SoeOptional}, // pseudo-account designator
|
||||
{sfVaultID, SoeOptional}, // pseudo-account designator
|
||||
{sfLoanBrokerID, SoeOptional}, // pseudo-account designator
|
||||
{sfContractID, SoeOptional}, // pseudo-account designator
|
||||
}))
|
||||
|
||||
/** A ledger object which contains a list of object identifiers.
|
||||
@@ -309,6 +310,11 @@ LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({
|
||||
{sfBaseFeeDrops, SoeOptional},
|
||||
{sfReserveBaseDrops, SoeOptional},
|
||||
{sfReserveIncrementDrops, SoeOptional},
|
||||
// Smart Escrow fields
|
||||
{sfGasLimit, SoeOptional},
|
||||
{sfBytecodeSizeLimit, SoeOptional},
|
||||
{sfGasPrice, SoeOptional},
|
||||
|
||||
{sfPreviousTxnID, SoeOptional},
|
||||
{sfPreviousTxnLgrSeq, SoeOptional},
|
||||
}))
|
||||
@@ -339,6 +345,8 @@ LEDGER_ENTRY(ltESCROW, 0x0075, Escrow, escrow, ({
|
||||
{sfCondition, SoeOptional},
|
||||
{sfCancelAfter, SoeOptional},
|
||||
{sfFinishAfter, SoeOptional},
|
||||
{sfBytecode, SoeOptional},
|
||||
{sfData, SoeOptional},
|
||||
{sfSourceTag, SoeOptional},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
@@ -510,6 +518,48 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
|
||||
// no PermissionedDomainID ever (use MPTIssuance.sfDomainID)
|
||||
}))
|
||||
|
||||
|
||||
|
||||
/** A ledger object representing a contract source.
|
||||
\sa keylet::contractSource
|
||||
*/
|
||||
LEDGER_ENTRY(ltCONTRACT_SOURCE, 0x0085, ContractSource, contract_source, ({
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfContractHash, SoeRequired},
|
||||
{sfContractCode, SoeRequired},
|
||||
{sfFunctions, SoeRequired},
|
||||
{sfInstanceParameters, SoeOptional},
|
||||
{sfReferenceCount, SoeRequired},
|
||||
}))
|
||||
|
||||
/** A ledger object representing a contract.
|
||||
\sa keylet::contract
|
||||
*/
|
||||
LEDGER_ENTRY(ltCONTRACT, 0x0086, Contract, contract, ({
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfSequence, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfOwner, SoeRequired},
|
||||
{sfContractAccount, SoeRequired},
|
||||
{sfContractHash, SoeRequired},
|
||||
{sfInstanceParameterValues, SoeOptional},
|
||||
{sfURI, SoeOptional},
|
||||
}))
|
||||
|
||||
/** A ledger object representing a contract data.
|
||||
\sa keylet::contractData
|
||||
*/
|
||||
LEDGER_ENTRY(ltCONTRACT_DATA, 0x0087, ContractData, contract_data, ({
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfOwner, SoeRequired},
|
||||
{sfContractAccount, SoeRequired},
|
||||
{sfContractJson, SoeRequired},
|
||||
}))
|
||||
|
||||
/** Reserve 0x0084-0x0087 for future Vault-related objects. */
|
||||
|
||||
/** A ledger object representing a loan broker
|
||||
|
||||
@@ -23,9 +23,10 @@ TYPED_SFIELD(sfLEVersion, UINT8, 6)
|
||||
// 8-bit integers (uncommon)
|
||||
TYPED_SFIELD(sfTickSize, UINT8, 16)
|
||||
TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17)
|
||||
TYPED_SFIELD(sfHookResult, UINT8, 18)
|
||||
// 18 unused
|
||||
TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19)
|
||||
TYPED_SFIELD(sfWithdrawalPolicy, UINT8, 20)
|
||||
TYPED_SFIELD(sfContractResult, UINT8, 21)
|
||||
|
||||
// 16-bit integers (common)
|
||||
TYPED_SFIELD(sfLedgerEntryType, UINT16, 1, SField::kSmdNever)
|
||||
@@ -37,10 +38,7 @@ TYPED_SFIELD(sfDiscountedFee, UINT16, 6)
|
||||
|
||||
// 16-bit integers (uncommon)
|
||||
TYPED_SFIELD(sfVersion, UINT16, 16)
|
||||
TYPED_SFIELD(sfHookStateChangeCount, UINT16, 17)
|
||||
TYPED_SFIELD(sfHookEmitCount, UINT16, 18)
|
||||
TYPED_SFIELD(sfHookExecutionIndex, UINT16, 19)
|
||||
TYPED_SFIELD(sfHookApiVersion, UINT16, 20)
|
||||
// 17 to 20 unused
|
||||
TYPED_SFIELD(sfLedgerFixType, UINT16, 21)
|
||||
TYPED_SFIELD(sfManagementFeeRate, UINT16, 22) // 1/10 basis points (bips)
|
||||
|
||||
@@ -91,9 +89,7 @@ TYPED_SFIELD(sfTicketSequence, UINT32, 41)
|
||||
TYPED_SFIELD(sfNFTokenTaxon, UINT32, 42)
|
||||
TYPED_SFIELD(sfMintedNFTokens, UINT32, 43)
|
||||
TYPED_SFIELD(sfBurnedNFTokens, UINT32, 44)
|
||||
TYPED_SFIELD(sfHookStateCount, UINT32, 45)
|
||||
TYPED_SFIELD(sfEmitGeneration, UINT32, 46)
|
||||
// 47 reserved for Hooks
|
||||
// 45 to 47 unused
|
||||
TYPED_SFIELD(sfVoteWeight, UINT32, 48)
|
||||
TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50)
|
||||
TYPED_SFIELD(sfOracleDocumentID, UINT32, 51)
|
||||
@@ -120,6 +116,12 @@ TYPED_SFIELD(sfSponsoringOwnerCount, UINT32, 71)
|
||||
TYPED_SFIELD(sfSponsoringAccountCount, UINT32, 72)
|
||||
TYPED_SFIELD(sfRemainingOwnerCount, UINT32, 73)
|
||||
TYPED_SFIELD(sfSponsorFlags, UINT32, 74)
|
||||
TYPED_SFIELD(sfGasLimit, UINT32, 75)
|
||||
TYPED_SFIELD(sfBytecodeSizeLimit, UINT32, 76)
|
||||
TYPED_SFIELD(sfGasPrice, UINT32, 77)
|
||||
TYPED_SFIELD(sfGas, UINT32, 78)
|
||||
TYPED_SFIELD(sfGasUsed, UINT32, 79)
|
||||
TYPED_SFIELD(sfParameterFlag, UINT32, 80)
|
||||
|
||||
// 64-bit integers (common)
|
||||
TYPED_SFIELD(sfIndexNext, UINT64, 1)
|
||||
@@ -137,9 +139,7 @@ TYPED_SFIELD(sfNFTokenOfferNode, UINT64, 12)
|
||||
TYPED_SFIELD(sfEmitBurden, UINT64, 13)
|
||||
|
||||
// 64-bit integers (uncommon)
|
||||
TYPED_SFIELD(sfHookOn, UINT64, 16)
|
||||
TYPED_SFIELD(sfHookInstructionCount, UINT64, 17)
|
||||
TYPED_SFIELD(sfHookReturnCode, UINT64, 18)
|
||||
// 16 to 18 unused
|
||||
TYPED_SFIELD(sfReferenceCount, UINT64, 19)
|
||||
TYPED_SFIELD(sfXChainClaimID, UINT64, 20)
|
||||
TYPED_SFIELD(sfXChainAccountCreateCount, UINT64, 21)
|
||||
@@ -203,10 +203,7 @@ TYPED_SFIELD(sfPreviousPageMin, UINT256, 26)
|
||||
TYPED_SFIELD(sfNextPageMin, UINT256, 27)
|
||||
TYPED_SFIELD(sfNFTokenBuyOffer, UINT256, 28)
|
||||
TYPED_SFIELD(sfNFTokenSellOffer, UINT256, 29)
|
||||
TYPED_SFIELD(sfHookStateKey, UINT256, 30)
|
||||
TYPED_SFIELD(sfHookHash, UINT256, 31)
|
||||
TYPED_SFIELD(sfHookNamespace, UINT256, 32)
|
||||
TYPED_SFIELD(sfHookSetTxnID, UINT256, 33)
|
||||
// 30 to 33 unused
|
||||
TYPED_SFIELD(sfDomainID, UINT256, 34)
|
||||
TYPED_SFIELD(sfVaultID, UINT256, 35,
|
||||
SField::kSmdPseudoAccount | SField::kSmdDefault)
|
||||
@@ -217,6 +214,9 @@ TYPED_SFIELD(sfLoanID, UINT256, 38)
|
||||
TYPED_SFIELD(sfReferenceHolding, UINT256, 39)
|
||||
TYPED_SFIELD(sfBlindingFactor, UINT256, 40)
|
||||
TYPED_SFIELD(sfObjectID, UINT256, 41)
|
||||
TYPED_SFIELD(sfContractHash, UINT256, 42)
|
||||
TYPED_SFIELD(sfContractID, UINT256, 43,
|
||||
SField::kSmdPseudoAccount | SField::kSmdDefault)
|
||||
|
||||
// number (common)
|
||||
TYPED_SFIELD(sfNumber, NUMBER, 1)
|
||||
@@ -237,9 +237,10 @@ TYPED_SFIELD(sfTotalValueOutstanding, NUMBER, 15, SField::kSmdNeedsAsset
|
||||
TYPED_SFIELD(sfPeriodicPayment, NUMBER, 16)
|
||||
TYPED_SFIELD(sfManagementFeeOutstanding, NUMBER, 17, SField::kSmdNeedsAsset | SField::kSmdDefault)
|
||||
|
||||
// int32
|
||||
// 32-bit signed (common)
|
||||
TYPED_SFIELD(sfLoanScale, INT32, 1)
|
||||
TYPED_SFIELD(sfRemainingOwnerCountDelta, INT32, 2)
|
||||
TYPED_SFIELD(sfVMReturnCode, INT32, 3)
|
||||
|
||||
// currency amount (common)
|
||||
TYPED_SFIELD(sfAmount, AMOUNT, 1)
|
||||
@@ -261,15 +262,13 @@ TYPED_SFIELD(sfMinimumOffer, AMOUNT, 16)
|
||||
TYPED_SFIELD(sfRippleEscrow, AMOUNT, 17)
|
||||
TYPED_SFIELD(sfDeliveredAmount, AMOUNT, 18)
|
||||
TYPED_SFIELD(sfNFTokenBrokerFee, AMOUNT, 19)
|
||||
|
||||
// Reserve 20 & 21 for Hooks.
|
||||
|
||||
// 20 to 21 unused
|
||||
// currency amount (fees)
|
||||
TYPED_SFIELD(sfBaseFeeDrops, AMOUNT, 22)
|
||||
TYPED_SFIELD(sfReserveBaseDrops, AMOUNT, 23)
|
||||
TYPED_SFIELD(sfReserveIncrementDrops, AMOUNT, 24)
|
||||
|
||||
// currency amount (AMM)
|
||||
// currency amount (more)
|
||||
TYPED_SFIELD(sfLPTokenOut, AMOUNT, 25)
|
||||
TYPED_SFIELD(sfLPTokenIn, AMOUNT, 26)
|
||||
TYPED_SFIELD(sfEPrice, AMOUNT, 27)
|
||||
@@ -304,10 +303,7 @@ TYPED_SFIELD(sfMasterSignature, VL, 18, SField::kSmdDefault, SFi
|
||||
TYPED_SFIELD(sfUNLModifyValidator, VL, 19)
|
||||
TYPED_SFIELD(sfValidatorToDisable, VL, 20)
|
||||
TYPED_SFIELD(sfValidatorToReEnable, VL, 21)
|
||||
TYPED_SFIELD(sfHookStateData, VL, 22)
|
||||
TYPED_SFIELD(sfHookReturnString, VL, 23)
|
||||
TYPED_SFIELD(sfHookParameterName, VL, 24)
|
||||
TYPED_SFIELD(sfHookParameterValue, VL, 25)
|
||||
// 22 to 25 unused
|
||||
TYPED_SFIELD(sfDIDDocument, VL, 26)
|
||||
TYPED_SFIELD(sfData, VL, 27)
|
||||
TYPED_SFIELD(sfAssetClass, VL, 28)
|
||||
@@ -329,6 +325,9 @@ TYPED_SFIELD(sfAuditorEncryptedAmount, VL, 43)
|
||||
TYPED_SFIELD(sfAuditorEncryptionKey, VL, 44)
|
||||
TYPED_SFIELD(sfAmountCommitment, VL, 45)
|
||||
TYPED_SFIELD(sfBalanceCommitment, VL, 46)
|
||||
TYPED_SFIELD(sfBytecode, VL, 47)
|
||||
TYPED_SFIELD(sfContractCode, VL, 48)
|
||||
TYPED_SFIELD(sfFunctionName, VL, 49)
|
||||
|
||||
// account (common)
|
||||
TYPED_SFIELD(sfAccount, ACCOUNT, 1)
|
||||
@@ -345,7 +344,7 @@ TYPED_SFIELD(sfHolder, ACCOUNT, 11)
|
||||
TYPED_SFIELD(sfDelegate, ACCOUNT, 12)
|
||||
|
||||
// account (uncommon)
|
||||
TYPED_SFIELD(sfHookAccount, ACCOUNT, 16)
|
||||
// 16 unused
|
||||
TYPED_SFIELD(sfOtherChainSource, ACCOUNT, 18)
|
||||
TYPED_SFIELD(sfOtherChainDestination, ACCOUNT, 19)
|
||||
TYPED_SFIELD(sfAttestationSignerAccount, ACCOUNT, 20)
|
||||
@@ -360,6 +359,7 @@ TYPED_SFIELD(sfHighSponsor, ACCOUNT, 28)
|
||||
TYPED_SFIELD(sfLowSponsor, ACCOUNT, 29)
|
||||
TYPED_SFIELD(sfCounterpartySponsor, ACCOUNT, 30)
|
||||
TYPED_SFIELD(sfSponsee, ACCOUNT, 31)
|
||||
TYPED_SFIELD(sfContractAccount, ACCOUNT, 32)
|
||||
|
||||
// vector of 256-bit
|
||||
TYPED_SFIELD(sfIndexes, VECTOR256, 1, SField::kSmdNever)
|
||||
@@ -398,7 +398,7 @@ UNTYPED_SFIELD(sfMemo, OBJECT, 10)
|
||||
UNTYPED_SFIELD(sfSignerEntry, OBJECT, 11)
|
||||
UNTYPED_SFIELD(sfNFToken, OBJECT, 12)
|
||||
UNTYPED_SFIELD(sfEmitDetails, OBJECT, 13)
|
||||
UNTYPED_SFIELD(sfHook, OBJECT, 14)
|
||||
// 14 unused
|
||||
UNTYPED_SFIELD(sfPermission, OBJECT, 15)
|
||||
|
||||
// inner object (uncommon)
|
||||
@@ -406,11 +406,7 @@ UNTYPED_SFIELD(sfSigner, OBJECT, 16)
|
||||
// 17 unused
|
||||
UNTYPED_SFIELD(sfMajority, OBJECT, 18)
|
||||
UNTYPED_SFIELD(sfDisabledValidator, OBJECT, 19)
|
||||
UNTYPED_SFIELD(sfEmittedTxn, OBJECT, 20)
|
||||
UNTYPED_SFIELD(sfHookExecution, OBJECT, 21)
|
||||
UNTYPED_SFIELD(sfHookDefinition, OBJECT, 22)
|
||||
UNTYPED_SFIELD(sfHookParameter, OBJECT, 23)
|
||||
UNTYPED_SFIELD(sfHookGrant, OBJECT, 24)
|
||||
// 20 to 24 unused
|
||||
UNTYPED_SFIELD(sfVoteEntry, OBJECT, 25)
|
||||
UNTYPED_SFIELD(sfAuctionSlot, OBJECT, 26)
|
||||
UNTYPED_SFIELD(sfAuthAccount, OBJECT, 27)
|
||||
@@ -425,6 +421,10 @@ UNTYPED_SFIELD(sfBatchSigner, OBJECT, 35)
|
||||
UNTYPED_SFIELD(sfBook, OBJECT, 36)
|
||||
UNTYPED_SFIELD(sfCounterpartySignature, OBJECT, 37, SField::kSmdDefault, SField::kNotSigning)
|
||||
UNTYPED_SFIELD(sfSponsorSignature, OBJECT, 38, SField::kSmdDefault, SField::kNotSigning)
|
||||
UNTYPED_SFIELD(sfFunction, OBJECT, 39)
|
||||
UNTYPED_SFIELD(sfInstanceParameter, OBJECT, 40)
|
||||
UNTYPED_SFIELD(sfInstanceParameterValue, OBJECT, 41)
|
||||
UNTYPED_SFIELD(sfParameter, OBJECT, 42)
|
||||
|
||||
// array of objects (common)
|
||||
// ARRAY/1 is reserved for end of array
|
||||
@@ -438,16 +438,14 @@ UNTYPED_SFIELD(sfSufficient, ARRAY, 7)
|
||||
UNTYPED_SFIELD(sfAffectedNodes, ARRAY, 8)
|
||||
UNTYPED_SFIELD(sfMemos, ARRAY, 9)
|
||||
UNTYPED_SFIELD(sfNFTokens, ARRAY, 10)
|
||||
UNTYPED_SFIELD(sfHooks, ARRAY, 11)
|
||||
// 11 unused
|
||||
UNTYPED_SFIELD(sfVoteSlots, ARRAY, 12)
|
||||
UNTYPED_SFIELD(sfAdditionalBooks, ARRAY, 13)
|
||||
|
||||
// array of objects (uncommon)
|
||||
UNTYPED_SFIELD(sfMajorities, ARRAY, 16)
|
||||
UNTYPED_SFIELD(sfDisabledValidators, ARRAY, 17)
|
||||
UNTYPED_SFIELD(sfHookExecutions, ARRAY, 18)
|
||||
UNTYPED_SFIELD(sfHookParameters, ARRAY, 19)
|
||||
UNTYPED_SFIELD(sfHookGrants, ARRAY, 20)
|
||||
// 18 to 20 unused
|
||||
UNTYPED_SFIELD(sfXChainClaimAttestations, ARRAY, 21)
|
||||
UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22)
|
||||
// 23 unused
|
||||
@@ -459,3 +457,16 @@ UNTYPED_SFIELD(sfAcceptedCredentials, ARRAY, 28)
|
||||
UNTYPED_SFIELD(sfPermissions, ARRAY, 29)
|
||||
UNTYPED_SFIELD(sfRawTransactions, ARRAY, 30)
|
||||
UNTYPED_SFIELD(sfBatchSigners, ARRAY, 31, SField::kSmdDefault, SField::kNotSigning)
|
||||
UNTYPED_SFIELD(sfFunctions, ARRAY, 32)
|
||||
UNTYPED_SFIELD(sfInstanceParameters, ARRAY, 33)
|
||||
UNTYPED_SFIELD(sfInstanceParameterValues,ARRAY, 34)
|
||||
UNTYPED_SFIELD(sfParameters, ARRAY, 35)
|
||||
|
||||
// data
|
||||
TYPED_SFIELD(sfParameterValue, DATA, 1, SField::kSmdDefault)
|
||||
|
||||
// data type
|
||||
TYPED_SFIELD(sfParameterType, DATATYPE, 1)
|
||||
|
||||
// json
|
||||
TYPED_SFIELD(sfContractJson, JSON, 1)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TRANSACTION(tag, value, name, delegable, amendments, privileges, fields)
|
||||
* TRANSACTION(tag, value, name, delegable, amendments, privileges, emitable, fields)
|
||||
*
|
||||
* To ease maintenance, you may replace any unneeded values with "..."
|
||||
* e.g. #define TRANSACTION(tag, value, name, ...)
|
||||
@@ -28,6 +28,7 @@ TRANSACTION(ttPAYMENT, 0, Payment,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
CreateAcct | MayCreateMpt,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfDestination, SoeRequired},
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
@@ -48,13 +49,16 @@ TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfDestination, SoeRequired},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
{sfCondition, SoeOptional},
|
||||
{sfCancelAfter, SoeOptional},
|
||||
{sfFinishAfter, SoeOptional},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfBytecode, SoeOptional},
|
||||
{sfData, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction type completes an existing escrow. */
|
||||
@@ -65,12 +69,14 @@ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfOwner, SoeRequired},
|
||||
{sfOfferSequence, SoeRequired},
|
||||
{sfFulfillment, SoeOptional},
|
||||
{sfCondition, SoeOptional},
|
||||
{sfCredentialIDs, SoeOptional},
|
||||
{sfGas, SoeOptional},
|
||||
}))
|
||||
|
||||
|
||||
@@ -82,6 +88,7 @@ TRANSACTION(ttACCOUNT_SET, 3, AccountSet,
|
||||
Delegation::NotDelegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfEmailHash, SoeOptional},
|
||||
{sfWalletLocator, SoeOptional},
|
||||
@@ -103,6 +110,7 @@ TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfOwner, SoeRequired},
|
||||
{sfOfferSequence, SoeRequired},
|
||||
@@ -116,6 +124,7 @@ TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey,
|
||||
Delegation::NotDelegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::notEmitable,
|
||||
({
|
||||
{sfRegularKey, SoeOptional},
|
||||
}))
|
||||
@@ -130,6 +139,7 @@ TRANSACTION(ttOFFER_CREATE, 7, OfferCreate,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
MayCreateMpt,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfTakerPays, SoeRequired, SoeMptSupported},
|
||||
{sfTakerGets, SoeRequired, SoeMptSupported},
|
||||
@@ -146,6 +156,7 @@ TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfOfferSequence, SoeRequired},
|
||||
}))
|
||||
@@ -160,6 +171,7 @@ TRANSACTION(ttTICKET_CREATE, 10, TicketCreate,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfTicketCount, SoeRequired},
|
||||
}))
|
||||
@@ -176,6 +188,7 @@ TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet,
|
||||
Delegation::NotDelegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::notEmitable,
|
||||
({
|
||||
{sfSignerQuorum, SoeRequired},
|
||||
{sfSignerEntries, SoeOptional},
|
||||
@@ -189,6 +202,7 @@ TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfDestination, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
@@ -206,6 +220,7 @@ TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfChannel, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
@@ -220,6 +235,7 @@ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfChannel, SoeRequired},
|
||||
{sfAmount, SoeOptional},
|
||||
@@ -237,6 +253,7 @@ TRANSACTION(ttCHECK_CREATE, 16, CheckCreate,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfDestination, SoeRequired},
|
||||
{sfSendMax, SoeRequired, SoeMptSupported},
|
||||
@@ -253,6 +270,7 @@ TRANSACTION(ttCHECK_CASH, 17, CheckCash,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
MayCreateMpt,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfCheckID, SoeRequired},
|
||||
{sfAmount, SoeOptional, SoeMptSupported},
|
||||
@@ -267,6 +285,7 @@ TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfCheckID, SoeRequired},
|
||||
}))
|
||||
@@ -279,6 +298,7 @@ TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::notEmitable,
|
||||
({
|
||||
{sfAuthorize, SoeOptional},
|
||||
{sfUnauthorize, SoeOptional},
|
||||
@@ -294,6 +314,7 @@ TRANSACTION(ttTRUST_SET, 20, TrustSet,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfLimitAmount, SoeOptional},
|
||||
{sfQualityIn, SoeOptional},
|
||||
@@ -308,6 +329,7 @@ TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete,
|
||||
Delegation::NotDelegable,
|
||||
uint256{},
|
||||
MustDeleteAcct,
|
||||
Emittance::notEmitable,
|
||||
({
|
||||
{sfDestination, SoeRequired},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
@@ -324,6 +346,7 @@ TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
ChangeNftCounts,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfNFTokenTaxon, SoeRequired},
|
||||
{sfTransferFee, SoeOptional},
|
||||
@@ -342,6 +365,7 @@ TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
ChangeNftCounts,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfNFTokenID, SoeRequired},
|
||||
{sfOwner, SoeOptional},
|
||||
@@ -355,6 +379,7 @@ TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfNFTokenID, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
@@ -371,6 +396,7 @@ TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfNFTokenOffers, SoeRequired},
|
||||
}))
|
||||
@@ -383,6 +409,7 @@ TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfNFTokenBuyOffer, SoeOptional},
|
||||
{sfNFTokenSellOffer, SoeOptional},
|
||||
@@ -397,6 +424,7 @@ TRANSACTION(ttCLAWBACK, 30, Clawback,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
{sfHolder, SoeOptional},
|
||||
@@ -410,6 +438,7 @@ TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback,
|
||||
Delegation::Delegable,
|
||||
featureAMMClawback,
|
||||
MayDeleteAcct | OverrideFreeze | MayAuthorizeMpt,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfHolder, SoeRequired},
|
||||
{sfAsset, SoeRequired, SoeMptSupported},
|
||||
@@ -425,6 +454,7 @@ TRANSACTION(ttAMM_CREATE, 35, AMMCreate,
|
||||
Delegation::Delegable,
|
||||
featureAMM,
|
||||
CreatePseudoAcct | MayCreateMpt,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
{sfAmount2, SoeRequired, SoeMptSupported},
|
||||
@@ -439,6 +469,7 @@ TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit,
|
||||
Delegation::Delegable,
|
||||
featureAMM,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfAsset, SoeRequired, SoeMptSupported},
|
||||
{sfAsset2, SoeRequired, SoeMptSupported},
|
||||
@@ -457,6 +488,7 @@ TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw,
|
||||
Delegation::Delegable,
|
||||
featureAMM,
|
||||
MayDeleteAcct | MayAuthorizeMpt,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfAsset, SoeRequired, SoeMptSupported},
|
||||
{sfAsset2, SoeRequired, SoeMptSupported},
|
||||
@@ -474,6 +506,7 @@ TRANSACTION(ttAMM_VOTE, 38, AMMVote,
|
||||
Delegation::Delegable,
|
||||
featureAMM,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfAsset, SoeRequired, SoeMptSupported},
|
||||
{sfAsset2, SoeRequired, SoeMptSupported},
|
||||
@@ -488,6 +521,7 @@ TRANSACTION(ttAMM_BID, 39, AMMBid,
|
||||
Delegation::Delegable,
|
||||
featureAMM,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfAsset, SoeRequired, SoeMptSupported},
|
||||
{sfAsset2, SoeRequired, SoeMptSupported},
|
||||
@@ -504,6 +538,7 @@ TRANSACTION(ttAMM_DELETE, 40, AMMDelete,
|
||||
Delegation::Delegable,
|
||||
featureAMM,
|
||||
MustDeleteAcct | MayDeleteMpt,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfAsset, SoeRequired, SoeMptSupported},
|
||||
{sfAsset2, SoeRequired, SoeMptSupported},
|
||||
@@ -517,6 +552,7 @@ TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
@@ -528,6 +564,7 @@ TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
@@ -540,6 +577,7 @@ TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
@@ -553,6 +591,7 @@ TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
@@ -565,6 +604,7 @@ TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
CreateAcct,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
|
||||
@@ -586,6 +626,7 @@ TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
CreateAcct,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
|
||||
@@ -607,6 +648,7 @@ TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfSignatureReward, SoeOptional},
|
||||
@@ -618,6 +660,7 @@ TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge,
|
||||
Delegation::Delegable,
|
||||
featureXChainBridge,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
@@ -632,6 +675,7 @@ TRANSACTION(ttDID_SET, 49, DIDSet,
|
||||
Delegation::Delegable,
|
||||
featureDID,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfDIDDocument, SoeOptional},
|
||||
{sfURI, SoeOptional},
|
||||
@@ -646,6 +690,7 @@ TRANSACTION(ttDID_DELETE, 50, DIDDelete,
|
||||
Delegation::Delegable,
|
||||
featureDID,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({}))
|
||||
|
||||
/** This transaction type creates an Oracle instance */
|
||||
@@ -656,6 +701,7 @@ TRANSACTION(ttORACLE_SET, 51, OracleSet,
|
||||
Delegation::Delegable,
|
||||
featurePriceOracle,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfOracleDocumentID, SoeRequired},
|
||||
{sfProvider, SoeOptional},
|
||||
@@ -673,6 +719,7 @@ TRANSACTION(ttORACLE_DELETE, 52, OracleDelete,
|
||||
Delegation::Delegable,
|
||||
featurePriceOracle,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfOracleDocumentID, SoeRequired},
|
||||
}))
|
||||
@@ -685,6 +732,7 @@ TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix,
|
||||
Delegation::Delegable,
|
||||
fixNFTokenPageLinks,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfLedgerFixType, SoeRequired},
|
||||
{sfOwner, SoeOptional},
|
||||
@@ -699,6 +747,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate,
|
||||
Delegation::Delegable,
|
||||
featureMPTokensV1,
|
||||
CreateMptIssuance,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfAssetScale, SoeOptional},
|
||||
{sfTransferFee, SoeOptional},
|
||||
@@ -716,6 +765,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy,
|
||||
Delegation::Delegable,
|
||||
featureMPTokensV1,
|
||||
DestroyMptIssuance,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
}))
|
||||
@@ -728,6 +778,7 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet,
|
||||
Delegation::Delegable,
|
||||
featureMPTokensV1,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfHolder, SoeOptional},
|
||||
@@ -747,6 +798,7 @@ TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize,
|
||||
Delegation::Delegable,
|
||||
featureMPTokensV1,
|
||||
MustAuthorizeMpt,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfHolder, SoeOptional},
|
||||
@@ -760,6 +812,7 @@ TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate,
|
||||
Delegation::Delegable,
|
||||
featureCredentials,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfSubject, SoeRequired},
|
||||
{sfCredentialType, SoeRequired},
|
||||
@@ -775,6 +828,7 @@ TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept,
|
||||
Delegation::Delegable,
|
||||
featureCredentials,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfIssuer, SoeRequired},
|
||||
{sfCredentialType, SoeRequired},
|
||||
@@ -788,6 +842,7 @@ TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete,
|
||||
Delegation::Delegable,
|
||||
featureCredentials,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfSubject, SoeOptional},
|
||||
{sfIssuer, SoeOptional},
|
||||
@@ -802,6 +857,7 @@ TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify,
|
||||
Delegation::Delegable,
|
||||
featureDynamicNFT,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfNFTokenID, SoeRequired},
|
||||
{sfOwner, SoeOptional},
|
||||
@@ -816,6 +872,7 @@ TRANSACTION(ttPERMISSIONED_DOMAIN_SET, 62, PermissionedDomainSet,
|
||||
Delegation::Delegable,
|
||||
featurePermissionedDomains,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfDomainID, SoeOptional},
|
||||
{sfAcceptedCredentials, SoeRequired},
|
||||
@@ -829,6 +886,7 @@ TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete,
|
||||
Delegation::Delegable,
|
||||
featurePermissionedDomains,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfDomainID, SoeRequired},
|
||||
}))
|
||||
@@ -841,6 +899,7 @@ TRANSACTION(ttDELEGATE_SET, 64, DelegateSet,
|
||||
Delegation::NotDelegable,
|
||||
featurePermissionDelegationV1_1,
|
||||
NoPriv,
|
||||
Emittance::notEmitable,
|
||||
({
|
||||
{sfAuthorize, SoeRequired},
|
||||
{sfPermissions, SoeRequired},
|
||||
@@ -854,6 +913,7 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
|
||||
Delegation::NotDelegable,
|
||||
featureSingleAssetVault,
|
||||
CreatePseudoAcct | CreateMptIssuance | MustModifyVault,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfAsset, SoeRequired, SoeMptSupported},
|
||||
{sfAssetsMaximum, SoeOptional},
|
||||
@@ -872,6 +932,7 @@ TRANSACTION(ttVAULT_SET, 66, VaultSet,
|
||||
Delegation::NotDelegable,
|
||||
featureSingleAssetVault,
|
||||
MustModifyVault,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfVaultID, SoeRequired},
|
||||
{sfAssetsMaximum, SoeOptional},
|
||||
@@ -887,6 +948,7 @@ TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
|
||||
Delegation::NotDelegable,
|
||||
featureSingleAssetVault,
|
||||
MustDeleteAcct | DestroyMptIssuance | MustModifyVault,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfVaultID, SoeRequired},
|
||||
{sfMemoData, SoeOptional},
|
||||
@@ -900,6 +962,7 @@ TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit,
|
||||
Delegation::NotDelegable,
|
||||
featureSingleAssetVault,
|
||||
MayAuthorizeMpt | MustModifyVault,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfVaultID, SoeRequired},
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
@@ -913,6 +976,7 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
|
||||
Delegation::NotDelegable,
|
||||
featureSingleAssetVault,
|
||||
MayDeleteMpt | MayAuthorizeMpt | MustModifyVault,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfVaultID, SoeRequired},
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
@@ -928,6 +992,7 @@ TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback,
|
||||
Delegation::NotDelegable,
|
||||
featureSingleAssetVault,
|
||||
MayDeleteMpt | MustModifyVault,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfVaultID, SoeRequired},
|
||||
{sfHolder, SoeRequired},
|
||||
@@ -942,6 +1007,7 @@ TRANSACTION(ttBATCH, 71, Batch,
|
||||
Delegation::NotDelegable,
|
||||
featureBatchV1_1,
|
||||
NoPriv,
|
||||
Emittance::notEmitable,
|
||||
({
|
||||
{sfRawTransactions, SoeRequired},
|
||||
{sfBatchSigners, SoeOptional},
|
||||
@@ -956,7 +1022,9 @@ TRANSACTION(ttBATCH, 71, Batch,
|
||||
TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
|
||||
Delegation::NotDelegable,
|
||||
featureLendingProtocol,
|
||||
CreatePseudoAcct | MayAuthorizeMpt, ({
|
||||
CreatePseudoAcct | MayAuthorizeMpt,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfVaultID, SoeRequired},
|
||||
{sfLoanBrokerID, SoeOptional},
|
||||
{sfData, SoeOptional},
|
||||
@@ -973,7 +1041,9 @@ TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
|
||||
TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete,
|
||||
Delegation::NotDelegable,
|
||||
featureLendingProtocol,
|
||||
MustDeleteAcct | MayAuthorizeMpt, ({
|
||||
MustDeleteAcct | MayAuthorizeMpt,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfLoanBrokerID, SoeRequired},
|
||||
}))
|
||||
|
||||
@@ -984,7 +1054,9 @@ TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete,
|
||||
TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit,
|
||||
Delegation::NotDelegable,
|
||||
featureLendingProtocol,
|
||||
NoPriv, ({
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfLoanBrokerID, SoeRequired},
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
}))
|
||||
@@ -996,7 +1068,9 @@ TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit,
|
||||
TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw,
|
||||
Delegation::NotDelegable,
|
||||
featureLendingProtocol,
|
||||
MayAuthorizeMpt, ({
|
||||
MayAuthorizeMpt,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfLoanBrokerID, SoeRequired},
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
{sfDestination, SoeOptional},
|
||||
@@ -1011,7 +1085,9 @@ TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw,
|
||||
TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback,
|
||||
Delegation::NotDelegable,
|
||||
featureLendingProtocol,
|
||||
NoPriv, ({
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfLoanBrokerID, SoeOptional},
|
||||
{sfAmount, SoeOptional, SoeMptSupported},
|
||||
}))
|
||||
@@ -1023,7 +1099,9 @@ TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback,
|
||||
TRANSACTION(ttLOAN_SET, 80, LoanSet,
|
||||
Delegation::NotDelegable,
|
||||
featureLendingProtocol,
|
||||
MayAuthorizeMpt | MustModifyVault, ({
|
||||
MayAuthorizeMpt | MustModifyVault,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfLoanBrokerID, SoeRequired},
|
||||
{sfData, SoeOptional},
|
||||
{sfCounterparty, SoeOptional},
|
||||
@@ -1050,7 +1128,9 @@ TRANSACTION(ttLOAN_SET, 80, LoanSet,
|
||||
TRANSACTION(ttLOAN_DELETE, 81, LoanDelete,
|
||||
Delegation::NotDelegable,
|
||||
featureLendingProtocol,
|
||||
NoPriv, ({
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfLoanID, SoeRequired},
|
||||
}))
|
||||
|
||||
@@ -1064,7 +1144,9 @@ TRANSACTION(ttLOAN_MANAGE, 82, LoanManage,
|
||||
// All of the LoanManage options will modify the vault, but the
|
||||
// transaction can succeed without options, essentially making it
|
||||
// a noop.
|
||||
MayModifyVault, ({
|
||||
MayModifyVault,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfLoanID, SoeRequired},
|
||||
}))
|
||||
|
||||
@@ -1075,7 +1157,9 @@ TRANSACTION(ttLOAN_MANAGE, 82, LoanManage,
|
||||
TRANSACTION(ttLOAN_PAY, 84, LoanPay,
|
||||
Delegation::NotDelegable,
|
||||
featureLendingProtocol,
|
||||
MayAuthorizeMpt | MustModifyVault, ({
|
||||
MayAuthorizeMpt | MustModifyVault,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfLoanID, SoeRequired},
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
}))
|
||||
@@ -1088,6 +1172,7 @@ TRANSACTION(ttCONFIDENTIAL_MPT_CONVERT, 85, ConfidentialMPTConvert,
|
||||
Delegation::NotDelegable,
|
||||
featureConfidentialTransfer,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfMPTAmount, SoeRequired},
|
||||
@@ -1107,6 +1192,7 @@ TRANSACTION(ttCONFIDENTIAL_MPT_MERGE_INBOX, 86, ConfidentialMPTMergeInbox,
|
||||
Delegation::Delegable,
|
||||
featureConfidentialTransfer,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
}))
|
||||
@@ -1119,6 +1205,7 @@ TRANSACTION(ttCONFIDENTIAL_MPT_CONVERT_BACK, 87, ConfidentialMPTConvertBack,
|
||||
Delegation::Delegable,
|
||||
featureConfidentialTransfer,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfMPTAmount, SoeRequired},
|
||||
@@ -1137,6 +1224,7 @@ TRANSACTION(ttCONFIDENTIAL_MPT_SEND, 88, ConfidentialMPTSend,
|
||||
Delegation::Delegable,
|
||||
featureConfidentialTransfer,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
@@ -1158,6 +1246,7 @@ TRANSACTION(ttCONFIDENTIAL_MPT_CLAWBACK, 89, ConfidentialMPTClawback,
|
||||
Delegation::Delegable,
|
||||
featureConfidentialTransfer,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfHolder, SoeRequired},
|
||||
@@ -1173,6 +1262,7 @@ TRANSACTION(ttSPONSORSHIP_TRANSFER, 90, SponsorshipTransfer,
|
||||
Delegation::NotDelegable,
|
||||
featureSponsor,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfObjectID, SoeOptional},
|
||||
{sfSponsee, SoeOptional},
|
||||
@@ -1186,6 +1276,7 @@ TRANSACTION(ttSPONSORSHIP_SET, 91, SponsorshipSet,
|
||||
Delegation::Delegable,
|
||||
featureSponsor,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfCounterpartySponsor, SoeOptional},
|
||||
{sfSponsee, SoeOptional},
|
||||
@@ -1194,6 +1285,101 @@ TRANSACTION(ttSPONSORSHIP_SET, 91, SponsorshipSet,
|
||||
{sfRemainingOwnerCountDelta, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction type creates the smart contract. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/contract/ContractCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONTRACT_CREATE, 92, ContractCreate,
|
||||
Delegation::Delegable,
|
||||
featureSmartContract,
|
||||
CreatePseudoAcct,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfContractCode, SoeOptional},
|
||||
{sfContractHash, SoeOptional},
|
||||
{sfFunctions, SoeOptional},
|
||||
{sfInstanceParameters, SoeOptional},
|
||||
{sfInstanceParameterValues, SoeOptional},
|
||||
{sfURI, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction type modifies the smart contract. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/contract/ContractModify.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONTRACT_MODIFY, 93, ContractModify,
|
||||
Delegation::Delegable,
|
||||
featureSmartContract,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfContractAccount, SoeOptional},
|
||||
{sfOwner, SoeOptional},
|
||||
{sfContractCode, SoeOptional},
|
||||
{sfContractHash, SoeOptional},
|
||||
{sfFunctions, SoeOptional},
|
||||
{sfInstanceParameters, SoeOptional},
|
||||
{sfInstanceParameterValues, SoeOptional},
|
||||
{sfURI, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction type deletes the smart contract. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/contract/ContractDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONTRACT_DELETE, 94, ContractDelete,
|
||||
Delegation::Delegable,
|
||||
featureSmartContract,
|
||||
MustDeleteAcct,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfContractAccount, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transaction type claws back funds from the contract. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/contract/ContractClawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONTRACT_CLAWBACK, 95, ContractClawback,
|
||||
Delegation::Delegable,
|
||||
featureSmartContract,
|
||||
NoPriv,
|
||||
Emittance::emitable,
|
||||
({
|
||||
{sfContractAccount, SoeOptional},
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
}))
|
||||
|
||||
/** This transaction type deletes user data. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/contract/ContractUserDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONTRACT_USER_DELETE, 96, ContractUserDelete,
|
||||
Delegation::Delegable,
|
||||
featureSmartContract,
|
||||
NoPriv,
|
||||
Emittance::notEmitable,
|
||||
({
|
||||
{sfContractAccount, SoeRequired},
|
||||
{sfGas, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transaction type calls the smart contract. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/contract/ContractCall.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONTRACT_CALL, 97, ContractCall,
|
||||
Delegation::Delegable,
|
||||
featureSmartContract,
|
||||
NoPriv,
|
||||
Emittance::notEmitable,
|
||||
({
|
||||
{sfContractAccount, SoeRequired},
|
||||
{sfFunctionName, SoeRequired},
|
||||
{sfParameters, SoeOptional},
|
||||
{sfGas, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This system-generated transaction type is used to update the status of the various amendments.
|
||||
|
||||
For details, see: https://xrpl.org/amendments.html
|
||||
@@ -1205,6 +1391,7 @@ TRANSACTION(ttAMENDMENT, 100, EnableAmendment,
|
||||
Delegation::NotDelegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::notEmitable,
|
||||
({
|
||||
{sfLedgerSequence, SoeRequired},
|
||||
{sfAmendment, SoeRequired},
|
||||
@@ -1217,6 +1404,7 @@ TRANSACTION(ttFEE, 101, SetFee,
|
||||
Delegation::NotDelegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::notEmitable,
|
||||
({
|
||||
{sfLedgerSequence, SoeOptional},
|
||||
// Old version uses raw numbers
|
||||
@@ -1228,6 +1416,10 @@ TRANSACTION(ttFEE, 101, SetFee,
|
||||
{sfBaseFeeDrops, SoeOptional},
|
||||
{sfReserveBaseDrops, SoeOptional},
|
||||
{sfReserveIncrementDrops, SoeOptional},
|
||||
// Smart Escrow fields
|
||||
{sfGasLimit, SoeOptional},
|
||||
{sfBytecodeSizeLimit, SoeOptional},
|
||||
{sfGasPrice, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This system-generated transaction type is used to update the network's negative UNL
|
||||
@@ -1238,6 +1430,7 @@ TRANSACTION(ttUNL_MODIFY, 102, UNLModify,
|
||||
Delegation::NotDelegable,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
Emittance::notEmitable,
|
||||
({
|
||||
{sfUNLModifyDisabling, SoeRequired},
|
||||
{sfLedgerSequence, SoeRequired},
|
||||
|
||||
@@ -189,6 +189,7 @@ JSS(confidential_balance_inbox); // out: mpt_holders (confidential MPT)
|
||||
JSS(confidential_balance_spending); // out: mpt_holders (confidential MPT)
|
||||
JSS(confidential_balance_version); // out: mpt_holders (confidential MPT)
|
||||
JSS(consensus); // out: NetworkOPs, LedgerConsensus
|
||||
JSS(contract_account); // out: ContractInfo
|
||||
JSS(converge_time); // out: NetworkOPs
|
||||
JSS(converge_time_s); // out: NetworkOPs
|
||||
JSS(cookie); // out: NetworkOPs
|
||||
@@ -252,6 +253,9 @@ JSS(expected_date); // out: any (warnings)
|
||||
JSS(expected_date_UTC); // out: any (warnings)
|
||||
JSS(expected_ledger_size); // out: TxQ
|
||||
JSS(expiration); // out: AccountOffers, AccountChannels, ValidatorList, amm_info
|
||||
JSS(gas_limit); // out: NetworkOPs
|
||||
JSS(bytecode_size_limit); // out: NetworkOPs
|
||||
JSS(gas_price); // out: NetworkOPs
|
||||
JSS(fail_hard); // in: Sign, Submit
|
||||
JSS(failed); // out: InboundLedger
|
||||
JSS(feature); // in: Feature
|
||||
@@ -278,6 +282,8 @@ JSS(frozen_balances); // out: GatewayBalances
|
||||
JSS(full); // in: LedgerClearer, handlers/Ledger
|
||||
JSS(full_reply); // out: PathFind
|
||||
JSS(fullbelow_size); // out: GetCounts
|
||||
JSS(function); // in: ContractInfo
|
||||
JSS(functions); // out: ContractInfo
|
||||
JSS(git); // out: server_info
|
||||
JSS(good); // out: RPCVersion
|
||||
JSS(hash); // out: NetworkOPs, InboundLedger, LedgerToJson, STTx; field
|
||||
@@ -560,6 +566,7 @@ JSS(size); // out: get_aggregate_price
|
||||
JSS(snapshot); // in: Subscribe
|
||||
JSS(source_account); // in: PathRequest, RipplePathFind
|
||||
JSS(source_amount); // in: PathRequest, RipplePathFind
|
||||
JSS(source_code_uri); // out: ContractInfo
|
||||
JSS(source_currencies); // in: PathRequest, RipplePathFind
|
||||
JSS(source_tag); // out: AccountChannels
|
||||
JSS(sponsee); // in: LedgerEntry
|
||||
@@ -660,6 +667,7 @@ JSS(url); // in/out: Subscribe, Unsubscribe
|
||||
JSS(url_password); // in: Subscribe
|
||||
JSS(url_username); // in: Subscribe
|
||||
JSS(urlgravatar); //
|
||||
JSS(user_data); // out: ContractInfo
|
||||
JSS(username); // in: Subscribe
|
||||
JSS(validated); // out: NetworkOPs, RPCHelpers, AccountTx*, Tx
|
||||
JSS(validator_list_expires); // out: NetworkOps, ValidatorList
|
||||
|
||||
@@ -590,6 +590,30 @@ public:
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfLoanBrokerID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfContractID (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT256::type::value_type>
|
||||
getContractID() const
|
||||
{
|
||||
if (hasContractID())
|
||||
return this->sle_->at(sfContractID);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfContractID is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasContractID() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfContractID);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -926,6 +950,17 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfContractID (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
AccountRootBuilder&
|
||||
setContractID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed AccountRoot wrapper.
|
||||
* @param index The ledger entry index.
|
||||
|
||||
336
include/xrpl/protocol_autogen/ledger_entries/Contract.h
Normal file
336
include/xrpl/protocol_autogen/ledger_entries/Contract.h
Normal file
@@ -0,0 +1,336 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBase.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::ledger_entries {
|
||||
|
||||
class ContractBuilder;
|
||||
|
||||
/**
|
||||
* @brief Ledger Entry: Contract
|
||||
*
|
||||
* Type: ltCONTRACT (0x0086)
|
||||
* RPC Name: contract
|
||||
*
|
||||
* Immutable wrapper around SLE providing type-safe field access.
|
||||
* Use ContractBuilder to construct new ledger entries.
|
||||
*/
|
||||
class Contract : public LedgerEntryBase
|
||||
{
|
||||
public:
|
||||
static constexpr LedgerEntryType entryType = ltCONTRACT;
|
||||
|
||||
/**
|
||||
* @brief Construct a Contract ledger entry wrapper from an existing SLE object.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
explicit Contract(SLE::const_pointer sle)
|
||||
: LedgerEntryBase(std::move(sle))
|
||||
{
|
||||
// Verify ledger entry type
|
||||
if (sle_->getType() != entryType)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for Contract");
|
||||
}
|
||||
}
|
||||
|
||||
// Ledger entry-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getPreviousTxnID() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getPreviousTxnLgrSeq() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSequence (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getSequence() const
|
||||
{
|
||||
return this->sle_->at(sfSequence);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwnerNode (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getOwnerNode() const
|
||||
{
|
||||
return this->sle_->at(sfOwnerNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwner (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getOwner() const
|
||||
{
|
||||
return this->sle_->at(sfOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfContractAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getContractAccount() const
|
||||
{
|
||||
return this->sle_->at(sfContractAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfContractHash (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getContractHash() const
|
||||
{
|
||||
return this->sle_->at(sfContractHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfInstanceParameterValues (SoeOptional)
|
||||
* @note This is an untyped field (unknown).
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::optional<std::reference_wrapper<STArray const>>
|
||||
getInstanceParameterValues() const
|
||||
{
|
||||
if (this->sle_->isFieldPresent(sfInstanceParameterValues))
|
||||
return this->sle_->getFieldArray(sfInstanceParameterValues);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfInstanceParameterValues is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasInstanceParameterValues() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfInstanceParameterValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfURI (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getURI() const
|
||||
{
|
||||
if (hasURI())
|
||||
return this->sle_->at(sfURI);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfURI is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasURI() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfURI);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for Contract ledger entries.
|
||||
*
|
||||
* Provides a fluent interface for constructing ledger entries with method chaining.
|
||||
* Uses STObject internally for flexible ledger entry construction.
|
||||
* Inherits common field setters from LedgerEntryBuilderBase.
|
||||
*/
|
||||
class ContractBuilder : public LedgerEntryBuilderBase<ContractBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ContractBuilder with required fields.
|
||||
* @param previousTxnID The sfPreviousTxnID field value.
|
||||
* @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value.
|
||||
* @param sequence The sfSequence field value.
|
||||
* @param ownerNode The sfOwnerNode field value.
|
||||
* @param owner The sfOwner field value.
|
||||
* @param contractAccount The sfContractAccount field value.
|
||||
* @param contractHash The sfContractHash field value.
|
||||
*/
|
||||
ContractBuilder(std::decay_t<typename SF_UINT256::type::value_type> const& previousTxnID,std::decay_t<typename SF_UINT32::type::value_type> const& previousTxnLgrSeq,std::decay_t<typename SF_UINT32::type::value_type> const& sequence,std::decay_t<typename SF_UINT64::type::value_type> const& ownerNode,std::decay_t<typename SF_ACCOUNT::type::value_type> const& owner,std::decay_t<typename SF_ACCOUNT::type::value_type> const& contractAccount,std::decay_t<typename SF_UINT256::type::value_type> const& contractHash)
|
||||
: LedgerEntryBuilderBase<ContractBuilder>(ltCONTRACT)
|
||||
{
|
||||
setPreviousTxnID(previousTxnID);
|
||||
setPreviousTxnLgrSeq(previousTxnLgrSeq);
|
||||
setSequence(sequence);
|
||||
setOwnerNode(ownerNode);
|
||||
setOwner(owner);
|
||||
setContractAccount(contractAccount);
|
||||
setContractHash(contractHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractBuilder from an existing SLE object.
|
||||
* @param sle The existing ledger entry to copy from.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
ContractBuilder(SLE::const_pointer sle)
|
||||
{
|
||||
if (sle->at(sfLedgerEntryType) != ltCONTRACT)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for Contract");
|
||||
}
|
||||
object_ = *sle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ledger entry-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractBuilder&
|
||||
setPreviousTxnID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractBuilder&
|
||||
setPreviousTxnLgrSeq(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnLgrSeq] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSequence (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractBuilder&
|
||||
setSequence(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSequence] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwnerNode (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractBuilder&
|
||||
setOwnerNode(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwnerNode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwner (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractBuilder&
|
||||
setOwner(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwner] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfContractAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractBuilder&
|
||||
setContractAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfContractHash (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractBuilder&
|
||||
setContractHash(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractHash] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfInstanceParameterValues (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractBuilder&
|
||||
setInstanceParameterValues(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfInstanceParameterValues, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfURI (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractBuilder&
|
||||
setURI(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfURI] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed Contract wrapper.
|
||||
* @param index The ledger entry index.
|
||||
* @return The constructed ledger entry wrapper.
|
||||
*/
|
||||
Contract
|
||||
build(uint256 const& index)
|
||||
{
|
||||
return Contract{std::make_shared<SLE>(std::move(object_), index)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::ledger_entries
|
||||
241
include/xrpl/protocol_autogen/ledger_entries/ContractData.h
Normal file
241
include/xrpl/protocol_autogen/ledger_entries/ContractData.h
Normal file
@@ -0,0 +1,241 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBase.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::ledger_entries {
|
||||
|
||||
class ContractDataBuilder;
|
||||
|
||||
/**
|
||||
* @brief Ledger Entry: ContractData
|
||||
*
|
||||
* Type: ltCONTRACT_DATA (0x0087)
|
||||
* RPC Name: contract_data
|
||||
*
|
||||
* Immutable wrapper around SLE providing type-safe field access.
|
||||
* Use ContractDataBuilder to construct new ledger entries.
|
||||
*/
|
||||
class ContractData : public LedgerEntryBase
|
||||
{
|
||||
public:
|
||||
static constexpr LedgerEntryType entryType = ltCONTRACT_DATA;
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractData ledger entry wrapper from an existing SLE object.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
explicit ContractData(SLE::const_pointer sle)
|
||||
: LedgerEntryBase(std::move(sle))
|
||||
{
|
||||
// Verify ledger entry type
|
||||
if (sle_->getType() != entryType)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for ContractData");
|
||||
}
|
||||
}
|
||||
|
||||
// Ledger entry-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getPreviousTxnID() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getPreviousTxnLgrSeq() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwnerNode (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getOwnerNode() const
|
||||
{
|
||||
return this->sle_->at(sfOwnerNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwner (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getOwner() const
|
||||
{
|
||||
return this->sle_->at(sfOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfContractAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getContractAccount() const
|
||||
{
|
||||
return this->sle_->at(sfContractAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfContractJson (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_JSON::type::value_type
|
||||
getContractJson() const
|
||||
{
|
||||
return this->sle_->at(sfContractJson);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ContractData ledger entries.
|
||||
*
|
||||
* Provides a fluent interface for constructing ledger entries with method chaining.
|
||||
* Uses STObject internally for flexible ledger entry construction.
|
||||
* Inherits common field setters from LedgerEntryBuilderBase.
|
||||
*/
|
||||
class ContractDataBuilder : public LedgerEntryBuilderBase<ContractDataBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ContractDataBuilder with required fields.
|
||||
* @param previousTxnID The sfPreviousTxnID field value.
|
||||
* @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value.
|
||||
* @param ownerNode The sfOwnerNode field value.
|
||||
* @param owner The sfOwner field value.
|
||||
* @param contractAccount The sfContractAccount field value.
|
||||
* @param contractJson The sfContractJson field value.
|
||||
*/
|
||||
ContractDataBuilder(std::decay_t<typename SF_UINT256::type::value_type> const& previousTxnID,std::decay_t<typename SF_UINT32::type::value_type> const& previousTxnLgrSeq,std::decay_t<typename SF_UINT64::type::value_type> const& ownerNode,std::decay_t<typename SF_ACCOUNT::type::value_type> const& owner,std::decay_t<typename SF_ACCOUNT::type::value_type> const& contractAccount,std::decay_t<typename SF_JSON::type::value_type> const& contractJson)
|
||||
: LedgerEntryBuilderBase<ContractDataBuilder>(ltCONTRACT_DATA)
|
||||
{
|
||||
setPreviousTxnID(previousTxnID);
|
||||
setPreviousTxnLgrSeq(previousTxnLgrSeq);
|
||||
setOwnerNode(ownerNode);
|
||||
setOwner(owner);
|
||||
setContractAccount(contractAccount);
|
||||
setContractJson(contractJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractDataBuilder from an existing SLE object.
|
||||
* @param sle The existing ledger entry to copy from.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
ContractDataBuilder(SLE::const_pointer sle)
|
||||
{
|
||||
if (sle->at(sfLedgerEntryType) != ltCONTRACT_DATA)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for ContractData");
|
||||
}
|
||||
object_ = *sle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ledger entry-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractDataBuilder&
|
||||
setPreviousTxnID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractDataBuilder&
|
||||
setPreviousTxnLgrSeq(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnLgrSeq] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwnerNode (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractDataBuilder&
|
||||
setOwnerNode(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwnerNode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwner (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractDataBuilder&
|
||||
setOwner(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwner] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfContractAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractDataBuilder&
|
||||
setContractAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfContractJson (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractDataBuilder&
|
||||
setContractJson(std::decay_t<typename SF_JSON::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractJson] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed ContractData wrapper.
|
||||
* @param index The ledger entry index.
|
||||
* @return The constructed ledger entry wrapper.
|
||||
*/
|
||||
ContractData
|
||||
build(uint256 const& index)
|
||||
{
|
||||
return ContractData{std::make_shared<SLE>(std::move(object_), index)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::ledger_entries
|
||||
278
include/xrpl/protocol_autogen/ledger_entries/ContractSource.h
Normal file
278
include/xrpl/protocol_autogen/ledger_entries/ContractSource.h
Normal file
@@ -0,0 +1,278 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBase.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::ledger_entries {
|
||||
|
||||
class ContractSourceBuilder;
|
||||
|
||||
/**
|
||||
* @brief Ledger Entry: ContractSource
|
||||
*
|
||||
* Type: ltCONTRACT_SOURCE (0x0085)
|
||||
* RPC Name: contract_source
|
||||
*
|
||||
* Immutable wrapper around SLE providing type-safe field access.
|
||||
* Use ContractSourceBuilder to construct new ledger entries.
|
||||
*/
|
||||
class ContractSource : public LedgerEntryBase
|
||||
{
|
||||
public:
|
||||
static constexpr LedgerEntryType entryType = ltCONTRACT_SOURCE;
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractSource ledger entry wrapper from an existing SLE object.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
explicit ContractSource(SLE::const_pointer sle)
|
||||
: LedgerEntryBase(std::move(sle))
|
||||
{
|
||||
// Verify ledger entry type
|
||||
if (sle_->getType() != entryType)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for ContractSource");
|
||||
}
|
||||
}
|
||||
|
||||
// Ledger entry-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getPreviousTxnID() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getPreviousTxnLgrSeq() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfContractHash (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getContractHash() const
|
||||
{
|
||||
return this->sle_->at(sfContractHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfContractCode (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getContractCode() const
|
||||
{
|
||||
return this->sle_->at(sfContractCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfFunctions (SoeRequired)
|
||||
* @note This is an untyped field (unknown).
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
STArray const&
|
||||
getFunctions() const
|
||||
{
|
||||
return this->sle_->getFieldArray(sfFunctions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfInstanceParameters (SoeOptional)
|
||||
* @note This is an untyped field (unknown).
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::optional<std::reference_wrapper<STArray const>>
|
||||
getInstanceParameters() const
|
||||
{
|
||||
if (this->sle_->isFieldPresent(sfInstanceParameters))
|
||||
return this->sle_->getFieldArray(sfInstanceParameters);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfInstanceParameters is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasInstanceParameters() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfInstanceParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfReferenceCount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getReferenceCount() const
|
||||
{
|
||||
return this->sle_->at(sfReferenceCount);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ContractSource ledger entries.
|
||||
*
|
||||
* Provides a fluent interface for constructing ledger entries with method chaining.
|
||||
* Uses STObject internally for flexible ledger entry construction.
|
||||
* Inherits common field setters from LedgerEntryBuilderBase.
|
||||
*/
|
||||
class ContractSourceBuilder : public LedgerEntryBuilderBase<ContractSourceBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ContractSourceBuilder with required fields.
|
||||
* @param previousTxnID The sfPreviousTxnID field value.
|
||||
* @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value.
|
||||
* @param contractHash The sfContractHash field value.
|
||||
* @param contractCode The sfContractCode field value.
|
||||
* @param functions The sfFunctions field value.
|
||||
* @param referenceCount The sfReferenceCount field value.
|
||||
*/
|
||||
ContractSourceBuilder(std::decay_t<typename SF_UINT256::type::value_type> const& previousTxnID,std::decay_t<typename SF_UINT32::type::value_type> const& previousTxnLgrSeq,std::decay_t<typename SF_UINT256::type::value_type> const& contractHash,std::decay_t<typename SF_VL::type::value_type> const& contractCode,STArray const& functions,std::decay_t<typename SF_UINT64::type::value_type> const& referenceCount)
|
||||
: LedgerEntryBuilderBase<ContractSourceBuilder>(ltCONTRACT_SOURCE)
|
||||
{
|
||||
setPreviousTxnID(previousTxnID);
|
||||
setPreviousTxnLgrSeq(previousTxnLgrSeq);
|
||||
setContractHash(contractHash);
|
||||
setContractCode(contractCode);
|
||||
setFunctions(functions);
|
||||
setReferenceCount(referenceCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractSourceBuilder from an existing SLE object.
|
||||
* @param sle The existing ledger entry to copy from.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
ContractSourceBuilder(SLE::const_pointer sle)
|
||||
{
|
||||
if (sle->at(sfLedgerEntryType) != ltCONTRACT_SOURCE)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for ContractSource");
|
||||
}
|
||||
object_ = *sle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ledger entry-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractSourceBuilder&
|
||||
setPreviousTxnID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractSourceBuilder&
|
||||
setPreviousTxnLgrSeq(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnLgrSeq] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfContractHash (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractSourceBuilder&
|
||||
setContractHash(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractHash] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfContractCode (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractSourceBuilder&
|
||||
setContractCode(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractCode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfFunctions (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractSourceBuilder&
|
||||
setFunctions(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfFunctions, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfInstanceParameters (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractSourceBuilder&
|
||||
setInstanceParameters(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfInstanceParameters, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfReferenceCount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractSourceBuilder&
|
||||
setReferenceCount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfReferenceCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed ContractSource wrapper.
|
||||
* @param index The ledger entry index.
|
||||
* @return The constructed ledger entry wrapper.
|
||||
*/
|
||||
ContractSource
|
||||
build(uint256 const& index)
|
||||
{
|
||||
return ContractSource{std::make_shared<SLE>(std::move(object_), index)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::ledger_entries
|
||||
@@ -174,6 +174,54 @@ public:
|
||||
return this->sle_->isFieldPresent(sfFinishAfter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfBytecode (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getBytecode() const
|
||||
{
|
||||
if (hasBytecode())
|
||||
return this->sle_->at(sfBytecode);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfBytecode is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasBytecode() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfBytecode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfData (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getData() const
|
||||
{
|
||||
if (hasData())
|
||||
return this->sle_->at(sfData);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfData is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasData() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSourceTag (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
@@ -453,6 +501,28 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfBytecode (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
EscrowBuilder&
|
||||
setBytecode(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfBytecode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfData (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
EscrowBuilder&
|
||||
setData(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfData] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSourceTag (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
|
||||
@@ -213,6 +213,78 @@ public:
|
||||
return this->sle_->isFieldPresent(sfReserveIncrementDrops);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfGasLimit (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getGasLimit() const
|
||||
{
|
||||
if (hasGasLimit())
|
||||
return this->sle_->at(sfGasLimit);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfGasLimit is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasGasLimit() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfGasLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfBytecodeSizeLimit (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getBytecodeSizeLimit() const
|
||||
{
|
||||
if (hasBytecodeSizeLimit())
|
||||
return this->sle_->at(sfBytecodeSizeLimit);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfBytecodeSizeLimit is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasBytecodeSizeLimit() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfBytecodeSizeLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfGasPrice (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getGasPrice() const
|
||||
{
|
||||
if (hasGasPrice())
|
||||
return this->sle_->at(sfGasPrice);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfGasPrice is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasGasPrice() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfGasPrice);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnID (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
@@ -375,6 +447,39 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfGasLimit (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
FeeSettingsBuilder&
|
||||
setGasLimit(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfGasLimit] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfBytecodeSizeLimit (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
FeeSettingsBuilder&
|
||||
setBytecodeSizeLimit(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfBytecodeSizeLimit] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfGasPrice (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
FeeSettingsBuilder&
|
||||
setGasPrice(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfGasPrice] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnID (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
|
||||
214
include/xrpl/protocol_autogen/transactions/ContractCall.h
Normal file
214
include/xrpl/protocol_autogen/transactions/ContractCall.h
Normal file
@@ -0,0 +1,214 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class ContractCallBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: ContractCall
|
||||
*
|
||||
* Type: ttCONTRACT_CALL (97)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureSmartContract
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use ContractCallBuilder to construct new transactions.
|
||||
*/
|
||||
class ContractCall : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttCONTRACT_CALL;
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractCall transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit ContractCall(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractCall");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfContractAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getContractAccount() const
|
||||
{
|
||||
return this->tx_->at(sfContractAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfFunctionName (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getFunctionName() const
|
||||
{
|
||||
return this->tx_->at(sfFunctionName);
|
||||
}
|
||||
/**
|
||||
* @brief Get sfParameters (SoeOptional)
|
||||
* @note This is an untyped field.
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::optional<std::reference_wrapper<STArray const>>
|
||||
getParameters() const
|
||||
{
|
||||
if (this->tx_->isFieldPresent(sfParameters))
|
||||
return this->tx_->getFieldArray(sfParameters);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfParameters is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasParameters() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfGas (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getGas() const
|
||||
{
|
||||
return this->tx_->at(sfGas);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ContractCall transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ContractCallBuilder : public TransactionBuilderBase<ContractCallBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ContractCallBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param contractAccount The sfContractAccount field value.
|
||||
* @param functionName The sfFunctionName field value.
|
||||
* @param gas The sfGas field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
ContractCallBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_ACCOUNT::type::value_type> const& contractAccount, std::decay_t<typename SF_VL::type::value_type> const& functionName, std::decay_t<typename SF_UINT32::type::value_type> const& gas, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<ContractCallBuilder>(ttCONTRACT_CALL, account, sequence, fee)
|
||||
{
|
||||
setContractAccount(contractAccount);
|
||||
setFunctionName(functionName);
|
||||
setGas(gas);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractCallBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
ContractCallBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttCONTRACT_CALL)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractCallBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfContractAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractCallBuilder&
|
||||
setContractAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfFunctionName (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractCallBuilder&
|
||||
setFunctionName(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfFunctionName] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfParameters (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractCallBuilder&
|
||||
setParameters(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfParameters, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfGas (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractCallBuilder&
|
||||
setGas(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfGas] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the ContractCall wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
ContractCall
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return ContractCall{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
170
include/xrpl/protocol_autogen/transactions/ContractClawback.h
Normal file
170
include/xrpl/protocol_autogen/transactions/ContractClawback.h
Normal file
@@ -0,0 +1,170 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class ContractClawbackBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: ContractClawback
|
||||
*
|
||||
* Type: ttCONTRACT_CLAWBACK (95)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureSmartContract
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use ContractClawbackBuilder to construct new transactions.
|
||||
*/
|
||||
class ContractClawback : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttCONTRACT_CLAWBACK;
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractClawback transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit ContractClawback(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractClawback");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfContractAccount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getContractAccount() const
|
||||
{
|
||||
if (hasContractAccount())
|
||||
{
|
||||
return this->tx_->at(sfContractAccount);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfContractAccount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasContractAccount() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfContractAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmount (SoeRequired)
|
||||
* @note This field supports MPT (Multi-Purpose Token) amounts.
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getAmount() const
|
||||
{
|
||||
return this->tx_->at(sfAmount);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ContractClawback transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ContractClawbackBuilder : public TransactionBuilderBase<ContractClawbackBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ContractClawbackBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param amount The sfAmount field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
ContractClawbackBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_AMOUNT::type::value_type> const& amount, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<ContractClawbackBuilder>(ttCONTRACT_CLAWBACK, account, sequence, fee)
|
||||
{
|
||||
setAmount(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractClawbackBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
ContractClawbackBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttCONTRACT_CLAWBACK)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractClawbackBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfContractAccount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractClawbackBuilder&
|
||||
setContractAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @note This field supports MPT (Multi-Purpose Token) amounts.
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractClawbackBuilder&
|
||||
setAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the ContractClawback wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
ContractClawback
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return ContractClawback{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
323
include/xrpl/protocol_autogen/transactions/ContractCreate.h
Normal file
323
include/xrpl/protocol_autogen/transactions/ContractCreate.h
Normal file
@@ -0,0 +1,323 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class ContractCreateBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: ContractCreate
|
||||
*
|
||||
* Type: ttCONTRACT_CREATE (92)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureSmartContract
|
||||
* Privileges: CreatePseudoAcct
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use ContractCreateBuilder to construct new transactions.
|
||||
*/
|
||||
class ContractCreate : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttCONTRACT_CREATE;
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractCreate transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit ContractCreate(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractCreate");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfContractCode (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getContractCode() const
|
||||
{
|
||||
if (hasContractCode())
|
||||
{
|
||||
return this->tx_->at(sfContractCode);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfContractCode is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasContractCode() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfContractCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfContractHash (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT256::type::value_type>
|
||||
getContractHash() const
|
||||
{
|
||||
if (hasContractHash())
|
||||
{
|
||||
return this->tx_->at(sfContractHash);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfContractHash is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasContractHash() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfContractHash);
|
||||
}
|
||||
/**
|
||||
* @brief Get sfFunctions (SoeOptional)
|
||||
* @note This is an untyped field.
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::optional<std::reference_wrapper<STArray const>>
|
||||
getFunctions() const
|
||||
{
|
||||
if (this->tx_->isFieldPresent(sfFunctions))
|
||||
return this->tx_->getFieldArray(sfFunctions);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfFunctions is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasFunctions() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfFunctions);
|
||||
}
|
||||
/**
|
||||
* @brief Get sfInstanceParameters (SoeOptional)
|
||||
* @note This is an untyped field.
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::optional<std::reference_wrapper<STArray const>>
|
||||
getInstanceParameters() const
|
||||
{
|
||||
if (this->tx_->isFieldPresent(sfInstanceParameters))
|
||||
return this->tx_->getFieldArray(sfInstanceParameters);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfInstanceParameters is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasInstanceParameters() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfInstanceParameters);
|
||||
}
|
||||
/**
|
||||
* @brief Get sfInstanceParameterValues (SoeOptional)
|
||||
* @note This is an untyped field.
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::optional<std::reference_wrapper<STArray const>>
|
||||
getInstanceParameterValues() const
|
||||
{
|
||||
if (this->tx_->isFieldPresent(sfInstanceParameterValues))
|
||||
return this->tx_->getFieldArray(sfInstanceParameterValues);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfInstanceParameterValues is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasInstanceParameterValues() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfInstanceParameterValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfURI (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getURI() const
|
||||
{
|
||||
if (hasURI())
|
||||
{
|
||||
return this->tx_->at(sfURI);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfURI is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasURI() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfURI);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ContractCreate transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ContractCreateBuilder : public TransactionBuilderBase<ContractCreateBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ContractCreateBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
ContractCreateBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<ContractCreateBuilder>(ttCONTRACT_CREATE, account, sequence, fee)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractCreateBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
ContractCreateBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttCONTRACT_CREATE)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractCreateBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfContractCode (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractCreateBuilder&
|
||||
setContractCode(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractCode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfContractHash (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractCreateBuilder&
|
||||
setContractHash(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractHash] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfFunctions (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractCreateBuilder&
|
||||
setFunctions(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfFunctions, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfInstanceParameters (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractCreateBuilder&
|
||||
setInstanceParameters(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfInstanceParameters, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfInstanceParameterValues (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractCreateBuilder&
|
||||
setInstanceParameterValues(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfInstanceParameterValues, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfURI (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractCreateBuilder&
|
||||
setURI(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfURI] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the ContractCreate wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
ContractCreate
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return ContractCreate{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
131
include/xrpl/protocol_autogen/transactions/ContractDelete.h
Normal file
131
include/xrpl/protocol_autogen/transactions/ContractDelete.h
Normal file
@@ -0,0 +1,131 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class ContractDeleteBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: ContractDelete
|
||||
*
|
||||
* Type: ttCONTRACT_DELETE (94)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureSmartContract
|
||||
* Privileges: MustDeleteAcct
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use ContractDeleteBuilder to construct new transactions.
|
||||
*/
|
||||
class ContractDelete : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttCONTRACT_DELETE;
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractDelete transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit ContractDelete(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractDelete");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfContractAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getContractAccount() const
|
||||
{
|
||||
return this->tx_->at(sfContractAccount);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ContractDelete transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ContractDeleteBuilder : public TransactionBuilderBase<ContractDeleteBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ContractDeleteBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param contractAccount The sfContractAccount field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
ContractDeleteBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_ACCOUNT::type::value_type> const& contractAccount, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<ContractDeleteBuilder>(ttCONTRACT_DELETE, account, sequence, fee)
|
||||
{
|
||||
setContractAccount(contractAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractDeleteBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
ContractDeleteBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttCONTRACT_DELETE)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractDeleteBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfContractAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractDeleteBuilder&
|
||||
setContractAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the ContractDelete wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
ContractDelete
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return ContractDelete{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
397
include/xrpl/protocol_autogen/transactions/ContractModify.h
Normal file
397
include/xrpl/protocol_autogen/transactions/ContractModify.h
Normal file
@@ -0,0 +1,397 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class ContractModifyBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: ContractModify
|
||||
*
|
||||
* Type: ttCONTRACT_MODIFY (93)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureSmartContract
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use ContractModifyBuilder to construct new transactions.
|
||||
*/
|
||||
class ContractModify : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttCONTRACT_MODIFY;
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractModify transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit ContractModify(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractModify");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfContractAccount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getContractAccount() const
|
||||
{
|
||||
if (hasContractAccount())
|
||||
{
|
||||
return this->tx_->at(sfContractAccount);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfContractAccount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasContractAccount() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfContractAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwner (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getOwner() const
|
||||
{
|
||||
if (hasOwner())
|
||||
{
|
||||
return this->tx_->at(sfOwner);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfOwner is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasOwner() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfContractCode (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getContractCode() const
|
||||
{
|
||||
if (hasContractCode())
|
||||
{
|
||||
return this->tx_->at(sfContractCode);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfContractCode is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasContractCode() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfContractCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfContractHash (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT256::type::value_type>
|
||||
getContractHash() const
|
||||
{
|
||||
if (hasContractHash())
|
||||
{
|
||||
return this->tx_->at(sfContractHash);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfContractHash is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasContractHash() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfContractHash);
|
||||
}
|
||||
/**
|
||||
* @brief Get sfFunctions (SoeOptional)
|
||||
* @note This is an untyped field.
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::optional<std::reference_wrapper<STArray const>>
|
||||
getFunctions() const
|
||||
{
|
||||
if (this->tx_->isFieldPresent(sfFunctions))
|
||||
return this->tx_->getFieldArray(sfFunctions);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfFunctions is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasFunctions() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfFunctions);
|
||||
}
|
||||
/**
|
||||
* @brief Get sfInstanceParameters (SoeOptional)
|
||||
* @note This is an untyped field.
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::optional<std::reference_wrapper<STArray const>>
|
||||
getInstanceParameters() const
|
||||
{
|
||||
if (this->tx_->isFieldPresent(sfInstanceParameters))
|
||||
return this->tx_->getFieldArray(sfInstanceParameters);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfInstanceParameters is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasInstanceParameters() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfInstanceParameters);
|
||||
}
|
||||
/**
|
||||
* @brief Get sfInstanceParameterValues (SoeOptional)
|
||||
* @note This is an untyped field.
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::optional<std::reference_wrapper<STArray const>>
|
||||
getInstanceParameterValues() const
|
||||
{
|
||||
if (this->tx_->isFieldPresent(sfInstanceParameterValues))
|
||||
return this->tx_->getFieldArray(sfInstanceParameterValues);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfInstanceParameterValues is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasInstanceParameterValues() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfInstanceParameterValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfURI (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getURI() const
|
||||
{
|
||||
if (hasURI())
|
||||
{
|
||||
return this->tx_->at(sfURI);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfURI is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasURI() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfURI);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ContractModify transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ContractModifyBuilder : public TransactionBuilderBase<ContractModifyBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ContractModifyBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
ContractModifyBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<ContractModifyBuilder>(ttCONTRACT_MODIFY, account, sequence, fee)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractModifyBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
ContractModifyBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttCONTRACT_MODIFY)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractModifyBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfContractAccount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractModifyBuilder&
|
||||
setContractAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwner (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractModifyBuilder&
|
||||
setOwner(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwner] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfContractCode (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractModifyBuilder&
|
||||
setContractCode(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractCode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfContractHash (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractModifyBuilder&
|
||||
setContractHash(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractHash] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfFunctions (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractModifyBuilder&
|
||||
setFunctions(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfFunctions, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfInstanceParameters (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractModifyBuilder&
|
||||
setInstanceParameters(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfInstanceParameters, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfInstanceParameterValues (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractModifyBuilder&
|
||||
setInstanceParameterValues(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfInstanceParameterValues, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfURI (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractModifyBuilder&
|
||||
setURI(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfURI] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the ContractModify wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
ContractModify
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return ContractModify{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
155
include/xrpl/protocol_autogen/transactions/ContractUserDelete.h
Normal file
155
include/xrpl/protocol_autogen/transactions/ContractUserDelete.h
Normal file
@@ -0,0 +1,155 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class ContractUserDeleteBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: ContractUserDelete
|
||||
*
|
||||
* Type: ttCONTRACT_USER_DELETE (96)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureSmartContract
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use ContractUserDeleteBuilder to construct new transactions.
|
||||
*/
|
||||
class ContractUserDelete : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttCONTRACT_USER_DELETE;
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractUserDelete transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit ContractUserDelete(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractUserDelete");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfContractAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getContractAccount() const
|
||||
{
|
||||
return this->tx_->at(sfContractAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfGas (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getGas() const
|
||||
{
|
||||
return this->tx_->at(sfGas);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ContractUserDelete transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ContractUserDeleteBuilder : public TransactionBuilderBase<ContractUserDeleteBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ContractUserDeleteBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param contractAccount The sfContractAccount field value.
|
||||
* @param gas The sfGas field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
ContractUserDeleteBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_ACCOUNT::type::value_type> const& contractAccount, std::decay_t<typename SF_UINT32::type::value_type> const& gas, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<ContractUserDeleteBuilder>(ttCONTRACT_USER_DELETE, account, sequence, fee)
|
||||
{
|
||||
setContractAccount(contractAccount);
|
||||
setGas(gas);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ContractUserDeleteBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
ContractUserDeleteBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttCONTRACT_USER_DELETE)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ContractUserDeleteBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfContractAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractUserDeleteBuilder&
|
||||
setContractAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfContractAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfGas (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ContractUserDeleteBuilder&
|
||||
setGas(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfGas] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the ContractUserDelete wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
ContractUserDelete
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return ContractUserDelete{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -58,6 +58,32 @@ public:
|
||||
return this->tx_->at(sfDestination);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestinationTag (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getDestinationTag() const
|
||||
{
|
||||
if (hasDestinationTag())
|
||||
{
|
||||
return this->tx_->at(sfDestinationTag);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfDestinationTag is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasDestinationTag() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfDestinationTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmount (SoeRequired)
|
||||
* @note This field supports MPT (Multi-Purpose Token) amounts.
|
||||
@@ -149,29 +175,55 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestinationTag (SoeOptional)
|
||||
* @brief Get sfBytecode (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getDestinationTag() const
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getBytecode() const
|
||||
{
|
||||
if (hasDestinationTag())
|
||||
if (hasBytecode())
|
||||
{
|
||||
return this->tx_->at(sfDestinationTag);
|
||||
return this->tx_->at(sfBytecode);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfDestinationTag is present.
|
||||
* @brief Check if sfBytecode is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasDestinationTag() const
|
||||
hasBytecode() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfDestinationTag);
|
||||
return this->tx_->isFieldPresent(sfBytecode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfData (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getData() const
|
||||
{
|
||||
if (hasData())
|
||||
{
|
||||
return this->tx_->at(sfData);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfData is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasData() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfData);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -232,6 +284,17 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestinationTag (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
EscrowCreateBuilder&
|
||||
setDestinationTag(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestinationTag] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @note This field supports MPT (Multi-Purpose Token) amounts.
|
||||
@@ -278,13 +341,24 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestinationTag (SoeOptional)
|
||||
* @brief Set sfBytecode (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
EscrowCreateBuilder&
|
||||
setDestinationTag(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
setBytecode(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestinationTag] = value;
|
||||
object_[sfBytecode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfData (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
EscrowCreateBuilder&
|
||||
setData(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfData] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,32 @@ public:
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfCredentialIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfGas (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getGas() const
|
||||
{
|
||||
if (hasGas())
|
||||
{
|
||||
return this->tx_->at(sfGas);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfGas is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasGas() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfGas);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -249,6 +275,17 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfGas (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
EscrowFinishBuilder&
|
||||
setGas(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfGas] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the EscrowFinish wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
|
||||
@@ -254,6 +254,84 @@ public:
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfReserveIncrementDrops);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfGasLimit (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getGasLimit() const
|
||||
{
|
||||
if (hasGasLimit())
|
||||
{
|
||||
return this->tx_->at(sfGasLimit);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfGasLimit is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasGasLimit() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfGasLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfBytecodeSizeLimit (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getBytecodeSizeLimit() const
|
||||
{
|
||||
if (hasBytecodeSizeLimit())
|
||||
{
|
||||
return this->tx_->at(sfBytecodeSizeLimit);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfBytecodeSizeLimit is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasBytecodeSizeLimit() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfBytecodeSizeLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfGasPrice (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getGasPrice() const
|
||||
{
|
||||
if (hasGasPrice())
|
||||
{
|
||||
return this->tx_->at(sfGasPrice);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfGasPrice is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasGasPrice() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfGasPrice);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -386,6 +464,39 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfGasLimit (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SetFeeBuilder&
|
||||
setGasLimit(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfGasLimit] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfBytecodeSizeLimit (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SetFeeBuilder&
|
||||
setBytecodeSizeLimit(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfBytecodeSizeLimit] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfGasPrice (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
SetFeeBuilder&
|
||||
setGasPrice(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfGasPrice] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the SetFee wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
|
||||
@@ -270,6 +270,11 @@ public:
|
||||
virtual bool
|
||||
unsubConsensus(std::uint64_t uListener) = 0;
|
||||
|
||||
virtual bool
|
||||
subContractEvent(ref ispListener) = 0;
|
||||
virtual bool
|
||||
unsubContractEvent(std::uint64_t uListener) = 0;
|
||||
|
||||
// VFALCO TODO Remove
|
||||
// This was added for one particular partner, it
|
||||
// "pushes" subscription data to a particular URL.
|
||||
|
||||
@@ -259,6 +259,9 @@ public:
|
||||
virtual void
|
||||
pubValidation(std::shared_ptr<STValidation> const& val) = 0;
|
||||
|
||||
virtual void
|
||||
pubContractEvent(std::string const& name, STJson const& event) = 0;
|
||||
|
||||
virtual void
|
||||
stateAccounting(json::Value& obj) = 0;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ApplyViewImpl.h>
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
#include <xrpl/ledger/OpenViewSandbox.h>
|
||||
#include <xrpl/ledger/RawView.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
@@ -15,8 +16,10 @@
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -60,6 +63,12 @@ public:
|
||||
XRPAmount const baseFee;
|
||||
beast::Journal const journal;
|
||||
|
||||
OpenView&
|
||||
openView()
|
||||
{
|
||||
return base_.view();
|
||||
}
|
||||
|
||||
ApplyView&
|
||||
view()
|
||||
{
|
||||
@@ -95,12 +104,51 @@ public:
|
||||
view_->deliver(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the gas used in the metadata
|
||||
*/
|
||||
void
|
||||
setGasUsed(std::uint32_t const gasUsed)
|
||||
{
|
||||
gasUsed_ = gasUsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the gas used in the metadata
|
||||
*/
|
||||
void
|
||||
setVMReturnCode(std::int32_t const vmReturnCode)
|
||||
{
|
||||
vmReturnCode_ = vmReturnCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transactions emitted by this transaction
|
||||
*/
|
||||
void
|
||||
setEmittedTxns(std::queue<std::shared_ptr<STTx const>> const emittedTxns)
|
||||
{
|
||||
emittedTxns_ = emittedTxns;
|
||||
}
|
||||
|
||||
std::queue<std::shared_ptr<STTx const>>
|
||||
getEmittedTxns()
|
||||
{
|
||||
return emittedTxns_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discard changes and start fresh.
|
||||
*/
|
||||
void
|
||||
discard();
|
||||
|
||||
/**
|
||||
* Finalize changes.
|
||||
*/
|
||||
void
|
||||
finalize();
|
||||
|
||||
/**
|
||||
* Apply the transaction result to the base.
|
||||
*/
|
||||
@@ -157,12 +205,15 @@ private:
|
||||
TER
|
||||
checkInvariantsHelper(TER const result, XRPAmount const fee, std::index_sequence<Is...>);
|
||||
|
||||
OpenView& base_;
|
||||
OpenViewSandbox base_;
|
||||
ApplyFlags flags_;
|
||||
std::optional<ApplyViewImpl> view_;
|
||||
|
||||
// The ID of the batch transaction we are executing under, if set.
|
||||
std::optional<uint256 const> parentBatchId_;
|
||||
std::optional<std::uint32_t> gasUsed_;
|
||||
std::optional<std::int32_t> vmReturnCode_;
|
||||
std::queue<std::shared_ptr<STTx const>> emittedTxns_;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class Application;
|
||||
|
||||
class HashRouter;
|
||||
class ServiceRegistry;
|
||||
|
||||
@@ -116,6 +118,22 @@ apply(
|
||||
ApplyFlags flags,
|
||||
beast::Journal journal);
|
||||
|
||||
/**
|
||||
* Apply a transaction that is part of a batch.
|
||||
*
|
||||
* @param parentBatchId The ID of the enclosing `Batch` transaction.
|
||||
*
|
||||
* @see apply
|
||||
*/
|
||||
ApplyResult
|
||||
apply(
|
||||
ServiceRegistry& registry,
|
||||
OpenView& view,
|
||||
uint256 const& parentBatchId,
|
||||
STTx const& tx,
|
||||
ApplyFlags flags,
|
||||
beast::Journal j);
|
||||
|
||||
/**
|
||||
* Enum class for return value from `applyTransaction`
|
||||
*
|
||||
|
||||
@@ -198,7 +198,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Invariant: An account XRP balance must be in XRP and take a value
|
||||
* between 0 and INITIAL_XRP drops, inclusive.
|
||||
* between 0 and kInitialXrp drops, inclusive.
|
||||
*
|
||||
* We iterate all account roots modified by the transaction and ensure that
|
||||
* their XRP balances are reasonable.
|
||||
@@ -290,7 +290,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Invariant: an escrow entry must take a value between 0 and
|
||||
* INITIAL_XRP drops exclusive.
|
||||
* kInitialXrp drops exclusive.
|
||||
*/
|
||||
class NoZeroEscrow
|
||||
{
|
||||
|
||||
42
include/xrpl/tx/transactors/DeleteUtils.h
Normal file
42
include/xrpl/tx/transactors/DeleteUtils.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Define a function pointer type that can be used to delete ledger node types.
|
||||
using DeleterFuncPtr = TER (*)(
|
||||
ServiceRegistry& registry,
|
||||
ApplyView& view,
|
||||
AccountID const& account,
|
||||
uint256 const& delIndex,
|
||||
std::shared_ptr<SLE> const& sleDel,
|
||||
beast::Journal j);
|
||||
|
||||
DeleterFuncPtr
|
||||
nonObligationDeleter(LedgerEntryType t);
|
||||
|
||||
TER
|
||||
deletePreclaim(
|
||||
PreclaimContext const& ctx,
|
||||
std::uint32_t seqDelta,
|
||||
AccountID const account,
|
||||
AccountID const dest,
|
||||
bool isPseudoAccount = false);
|
||||
|
||||
TER
|
||||
deleteDoApply(
|
||||
ApplyContext& applyCtx,
|
||||
STAmount const& accountBalance,
|
||||
AccountID const& account,
|
||||
AccountID const& dest);
|
||||
|
||||
} // namespace xrpl
|
||||
40
include/xrpl/tx/transactors/contract/ContractCall.h
Normal file
40
include/xrpl/tx/transactors/contract/ContractCall.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class ContractCall : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit ContractCall(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
37
include/xrpl/tx/transactors/contract/ContractClawback.h
Normal file
37
include/xrpl/tx/transactors/contract/ContractClawback.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class ContractClawback : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit ContractClawback(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
43
include/xrpl/tx/transactors/contract/ContractCreate.h
Normal file
43
include/xrpl/tx/transactors/contract/ContractCreate.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class ContractCreate : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit ContractCreate(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
45
include/xrpl/tx/transactors/contract/ContractDelete.h
Normal file
45
include/xrpl/tx/transactors/contract/ContractDelete.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class ContractDelete : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit ContractDelete(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
// Interface used by DeleteAccount
|
||||
static TER
|
||||
deleteContract(
|
||||
ApplyView& view,
|
||||
std::shared_ptr<SLE> const& sle,
|
||||
AccountID const& account,
|
||||
beast::Journal j);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
40
include/xrpl/tx/transactors/contract/ContractModify.h
Normal file
40
include/xrpl/tx/transactors/contract/ContractModify.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class ContractModify : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit ContractModify(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
37
include/xrpl/tx/transactors/contract/ContractUserDelete.h
Normal file
37
include/xrpl/tx/transactors/contract/ContractUserDelete.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class ContractUserDelete : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit ContractUserDelete(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -20,15 +20,21 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static bool
|
||||
checkExtraFeatures(PreflightContext const& ctx);
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflightSigValidated(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
|
||||
@@ -26,9 +26,6 @@ private:
|
||||
TER
|
||||
bridgeOffers(SLE::ref buy, SLE::ref sell);
|
||||
|
||||
TER
|
||||
transferNFToken(AccountID const& buyer, AccountID const& seller, uint256 const& nfTokenID);
|
||||
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
|
||||
100
include/xrpl/tx/wasm/ContractContext.h
Normal file
100
include/xrpl/tx/wasm/ContractContext.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
#include <xrpl/ledger/helpers/ContractUtils.h>
|
||||
#include <xrpl/protocol/STArray.h>
|
||||
#include <xrpl/protocol/STData.h>
|
||||
#include <xrpl/protocol/STDataType.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
|
||||
#include <queue>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
struct ParameterValueVec
|
||||
{
|
||||
STData const value;
|
||||
};
|
||||
|
||||
struct FunctionParameterValueVecWithName
|
||||
{
|
||||
Blob const name;
|
||||
STData const value;
|
||||
};
|
||||
|
||||
struct ParameterTypeVec
|
||||
{
|
||||
STDataType const type;
|
||||
};
|
||||
|
||||
std::vector<ParameterValueVec>
|
||||
getParameterValueVec(STArray const& functionParameters);
|
||||
|
||||
std::vector<ParameterTypeVec>
|
||||
getParameterTypeVec(STArray const& functionParameters);
|
||||
|
||||
enum ExitType : uint8_t {
|
||||
UNSET = 0,
|
||||
WASM_ERROR = 1,
|
||||
ROLLBACK = 2,
|
||||
ACCEPT = 3,
|
||||
};
|
||||
|
||||
struct ContractResult
|
||||
{
|
||||
uint256 const contractHash; // Hash of the contract code
|
||||
Keylet const contractKeylet; // Keylet for the contract instance
|
||||
Keylet const contractSourceKeylet; // Keylet for the contract source
|
||||
Keylet const contractAccountKeylet; // Keylet for the contract account
|
||||
AccountID const contractAccount; // AccountID of the contract account
|
||||
std::uint32_t nextSequence; // Next sequence number for the contract account
|
||||
AccountID const otxnAccount; // AccountID for the originating transaction
|
||||
uint256 const otxnId; // ID for the originating transaction
|
||||
std::string exitReason{""};
|
||||
int64_t exitCode{-1};
|
||||
ContractDataMap dataMap;
|
||||
ContractEventMap eventMap;
|
||||
std::queue<std::shared_ptr<STTx const>> emittedTxns{};
|
||||
std::size_t changedDataCount{0};
|
||||
};
|
||||
|
||||
struct ContractContext
|
||||
{
|
||||
ApplyContext& applyCtx;
|
||||
std::vector<ParameterValueVec> instanceParameters;
|
||||
std::vector<ParameterValueVec> functionParameters;
|
||||
std::vector<STObject> built_txns;
|
||||
int64_t expected_etxn_count{-1}; // expected emitted transaction count
|
||||
std::map<uint256, bool> nonce_used{}; // nonces used in this execution
|
||||
uint32_t generation = 0; // generation of the contract being executed
|
||||
uint64_t burden = 0; // computational burden used
|
||||
ContractResult result;
|
||||
|
||||
/**
|
||||
* Persistent view used to track cumulative state from emitted
|
||||
* transactions so that successive emits within the same WASM
|
||||
* execution see the correct sequence numbers, balances, etc.
|
||||
*/
|
||||
std::optional<OpenView> emitView;
|
||||
|
||||
/**
|
||||
* Return the emit view, lazily creating it on first use.
|
||||
*
|
||||
* The view is layered on top of the transactor's ApplyViewImpl
|
||||
* (applyCtx.view()) so that reads automatically fall through to
|
||||
* the transactor's pending state (e.g. the tfSendAmount balance
|
||||
* transfer, consumed sequence number, paid fee) without needing
|
||||
* to manually copy SLE changes.
|
||||
*/
|
||||
OpenView&
|
||||
getEmitView()
|
||||
{
|
||||
if (!emitView)
|
||||
emitView.emplace(static_cast<ReadView const*>(&applyCtx.view()));
|
||||
return *emitView;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
95
include/xrpl/tx/wasm/ContractHostFuncImpl.h
Normal file
95
include/xrpl/tx/wasm/ContractHostFuncImpl.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/wasm/ContractContext.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/HostFuncImpl.h>
|
||||
|
||||
namespace xrpl {
|
||||
class ContractHostFunctionsImpl : public WasmHostFunctionsImpl
|
||||
{
|
||||
ContractContext& contractCtx;
|
||||
uint256 const contractId = contractCtx.result.contractKeylet.key;
|
||||
|
||||
public:
|
||||
// Constructor for contract-specific functionality
|
||||
ContractHostFunctionsImpl(ContractContext& contractContext)
|
||||
: WasmHostFunctionsImpl(contractContext.applyCtx, contractContext.result.contractKeylet)
|
||||
, contractCtx(contractContext)
|
||||
{
|
||||
}
|
||||
|
||||
// std::expected<Bytes, HostFunctionError>
|
||||
// getFieldBytesFromSTData(xrpl::STData const& funcParam, std::uint32_t
|
||||
// stTypeId);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
instanceParam(std::uint32_t index, std::uint32_t stTypeId) override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
functionParam(std::uint32_t index, std::uint32_t stTypeId) override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getDataObjectField(AccountID const& account, std::string_view const& key) override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getDataNestedObjectField(
|
||||
AccountID const& account,
|
||||
std::string_view const& key,
|
||||
std::string_view const& nestedKey) override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getDataArrayElementField(AccountID const& account, size_t index, std::string_view const& key)
|
||||
override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getDataNestedArrayElementField(
|
||||
AccountID const& account,
|
||||
std::string_view const& key,
|
||||
size_t index,
|
||||
std::string_view const& nestedKey) override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
setDataObjectField(
|
||||
AccountID const& account,
|
||||
std::string_view const& key,
|
||||
STJson::Value const& value) override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
setDataNestedObjectField(
|
||||
AccountID const& account,
|
||||
std::string_view const& nestedKey,
|
||||
std::string_view const& key,
|
||||
STJson::Value const& value) override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
setDataArrayElementField(
|
||||
AccountID const& account,
|
||||
size_t index,
|
||||
std::string_view const& key,
|
||||
STJson::Value const& value) override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
setDataNestedArrayElementField(
|
||||
AccountID const& account,
|
||||
std::string_view const& key,
|
||||
size_t index,
|
||||
std::string_view const& nestedKey,
|
||||
STJson::Value const& value) override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
buildTxn(std::uint16_t const& txType) override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
addTxnField(std::uint32_t const& index, SField const& field, Slice const& data) override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
emitBuiltTxn(std::uint32_t const& index) override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
emitTxn(std::shared_ptr<STTx const> const& stxPtr) override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
emitEvent(std::string_view const& eventName, STJson const& eventData) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
617
include/xrpl/tx/wasm/HostFunc.h
Normal file
617
include/xrpl/tx/wasm/HostFunc.h
Normal file
@@ -0,0 +1,617 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STJson.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace wasm_float {
|
||||
|
||||
std::string
|
||||
floatToString(Slice const& data);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatFromIntImpl(int64_t x, int32_t mode);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatFromUintImpl(uint64_t x, int32_t mode);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatFromSTAmountImpl(STAmount const& x, int32_t mode);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatFromSTNumberImpl(STNumber const& x, int32_t mode);
|
||||
|
||||
std::expected<int64_t, HostFunctionError>
|
||||
floatToIntImpl(Slice const& x, int32_t mode);
|
||||
|
||||
std::expected<FloatPair, HostFunctionError>
|
||||
floatToMantExpImpl(Slice const& x);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatFromMantExpImpl(int64_t mantissa, int32_t exponent, int32_t mode);
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
floatCompareImpl(Slice const& x, Slice const& y);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatAddImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatSubtractImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatMultiplyImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatDivideImpl(Slice const& x, Slice const& y, int32_t mode);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatRootImpl(Slice const& x, int32_t n, int32_t mode);
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatPowerImpl(Slice const& x, int32_t n, int32_t mode);
|
||||
|
||||
} // namespace wasm_float
|
||||
|
||||
// Intended to work only through wasm runtime. Don't call them directly, except with unit tests
|
||||
class HostFunctions
|
||||
{
|
||||
protected:
|
||||
RTOptRef rt_;
|
||||
beast::Journal j_;
|
||||
|
||||
public:
|
||||
HostFunctions(beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) : j_(j)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
setRT(WasmRuntimeWrapper& rt)
|
||||
{
|
||||
rt_ = rt;
|
||||
}
|
||||
|
||||
void
|
||||
resetRT()
|
||||
{
|
||||
rt_ = std::nullopt;
|
||||
}
|
||||
|
||||
[[nodiscard]] WasmRuntimeWrapper&
|
||||
getRT() const
|
||||
{
|
||||
if (!rt_)
|
||||
Throw<std::logic_error>("Wasm runtime not set");
|
||||
return rt_->get();
|
||||
}
|
||||
|
||||
[[nodiscard]] beast::Journal
|
||||
getJournal() const
|
||||
{
|
||||
return j_;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
|
||||
[[nodiscard]] virtual bool
|
||||
checkSelf() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<std::uint32_t, HostFunctionError>
|
||||
getLedgerSqn() const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<std::uint32_t, HostFunctionError>
|
||||
getParentLedgerTime() const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Hash, HostFunctionError>
|
||||
getParentLedgerHash() const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<uint32_t, HostFunctionError>
|
||||
getBaseFee() const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(uint256 const& amendmentId) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(std::string_view const& amendmentName) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<int32_t, HostFunctionError>
|
||||
cacheLedgerObj(uint256 const& objId, int32_t cacheIdx)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
getTxField(SField const& fname) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjField(SField const& fname) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
getLedgerObjField(int32_t cacheIdx, SField const& fname) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
getTxNestedField(FieldLocator const& locator) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjNestedField(FieldLocator const& locator) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
getTxArrayLen(SField const& fname) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjArrayLen(SField const& fname) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
getTxNestedArrayLen(FieldLocator const& locator) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<int32_t, HostFunctionError>
|
||||
updateData(Slice const& data)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
checkSignature(Slice const& message, Slice const& signature, Slice const& pubkey) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Hash, HostFunctionError>
|
||||
computeSha512HalfHash(Slice const& data) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
accountKeylet(AccountID const& account) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
ammKeylet(Asset const& issue1, Asset const& issue2) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
checkKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
credentialKeylet(AccountID const& subject, AccountID const& issuer, Slice const& credentialType)
|
||||
const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
didKeylet(AccountID const& account) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
delegateKeylet(AccountID const& account, AccountID const& authorize) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
depositPreauthKeylet(AccountID const& account, AccountID const& authorize) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
escrowKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
trustLineKeylet(AccountID const& account1, AccountID const& account2, Currency const& currency)
|
||||
const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
mptokenIssuanceKeylet(AccountID const& issuer, std::uint32_t seq) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
mptokenKeylet(MPTID const& mptid, AccountID const& holder) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
nftokenOfferKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
offerKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
oracleKeylet(AccountID const& account, std::uint32_t docId) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
paychannelKeylet(AccountID const& account, AccountID const& destination, std::uint32_t seq)
|
||||
const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
permissionedDomainKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
signerListKeylet(AccountID const& account) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
ticketKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
vaultKeylet(AccountID const& account, std::uint32_t seq) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
getNFT(AccountID const& account, uint256 const& nftId) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
getNFTIssuer(uint256 const& nftId) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<std::uint32_t, HostFunctionError>
|
||||
getNFTTaxon(uint256 const& nftId) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
getNFTFlags(uint256 const& nftId) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
getNFTTransferFee(uint256 const& nftId) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<std::uint32_t, HostFunctionError>
|
||||
getNFTSequence(uint256 const& nftId) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
// A no-op rather than Unimplemented: trace only writes to the local log.
|
||||
// trace_wrap has already rendered the guest's buffer into `data`.
|
||||
virtual void
|
||||
trace(std::string_view const& msg, std::string_view const& data) const
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
floatFromInt(int64_t x, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
floatFromUint(uint64_t x, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
floatFromSTAmount(STAmount const& x, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
floatFromSTNumber(STNumber const& x, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int64_t, HostFunctionError>
|
||||
floatToInt(Slice const& x, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<FloatPair, HostFunctionError>
|
||||
floatToMantExp(Slice const& x) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<int32_t, HostFunctionError>
|
||||
floatCompare(Slice const& x, Slice const& y) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
floatAdd(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
floatSubtract(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
floatMultiply(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
floatDivide(Slice const& x, Slice const& y, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
floatRoot(Slice const& x, int32_t n, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::expected<Bytes, HostFunctionError>
|
||||
floatPower(Slice const& x, int32_t n, int32_t mode) const
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<Bytes, HostFunctionError>
|
||||
instanceParam(std::uint32_t index, std::uint32_t stTypeId)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<Bytes, HostFunctionError>
|
||||
functionParam(std::uint32_t index, std::uint32_t stTypeId)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<Bytes, HostFunctionError>
|
||||
getDataObjectField(AccountID const& account, std::string_view const& key)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<Bytes, HostFunctionError>
|
||||
getDataNestedObjectField(
|
||||
AccountID const& account,
|
||||
std::string_view const& key,
|
||||
std::string_view const& nestedKey)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<Bytes, HostFunctionError>
|
||||
getDataArrayElementField(AccountID const& account, size_t index, std::string_view const& key)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<Bytes, HostFunctionError>
|
||||
getDataNestedArrayElementField(
|
||||
AccountID const& account,
|
||||
std::string_view const& key,
|
||||
size_t index,
|
||||
std::string_view const& nestedKey)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<int32_t, HostFunctionError>
|
||||
setDataObjectField(
|
||||
AccountID const& account,
|
||||
std::string_view const& keyName,
|
||||
STJson::Value const& value)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<int32_t, HostFunctionError>
|
||||
setDataNestedObjectField(
|
||||
AccountID const& account,
|
||||
std::string_view const& nestedKey,
|
||||
std::string_view const& key,
|
||||
STJson::Value const& value)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<int32_t, HostFunctionError>
|
||||
setDataArrayElementField(
|
||||
AccountID const& account,
|
||||
size_t index,
|
||||
std::string_view const& key,
|
||||
STJson::Value const& value)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<int32_t, HostFunctionError>
|
||||
setDataNestedArrayElementField(
|
||||
AccountID const& account,
|
||||
std::string_view const& key,
|
||||
size_t index,
|
||||
std::string_view const& nestedKey,
|
||||
STJson::Value const& value)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<int32_t, HostFunctionError>
|
||||
buildTxn(std::uint16_t const& txType)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<int32_t, HostFunctionError>
|
||||
addTxnField(std::uint32_t const& index, SField const& field, Slice const& data)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<int32_t, HostFunctionError>
|
||||
emitBuiltTxn(std::uint32_t const& index)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<int32_t, HostFunctionError>
|
||||
emitTxn(std::shared_ptr<STTx const> const& stxPtr)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual std::expected<int32_t, HostFunctionError>
|
||||
emitEvent(std::string_view const& eventName, STJson const& eventData)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::Unimplemented);
|
||||
}
|
||||
|
||||
virtual ~HostFunctions() = default;
|
||||
// LCOV_EXCL_STOP
|
||||
};
|
||||
|
||||
using HFRef = std::reference_wrapper<HostFunctions>;
|
||||
|
||||
} // namespace xrpl
|
||||
290
include/xrpl/tx/wasm/HostFuncImpl.h
Normal file
290
include/xrpl/tx/wasm/HostFuncImpl.h
Normal file
@@ -0,0 +1,290 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Intended to work only through wasm runtime. Don't call them directly, except with unit tests
|
||||
class WasmHostFunctionsImpl : public HostFunctions
|
||||
{
|
||||
ApplyContext& ctx_;
|
||||
|
||||
Keylet leKey_;
|
||||
mutable std::optional<std::shared_ptr<SLE const>> currentLedgerObj_;
|
||||
|
||||
static int constexpr maxCache = 256;
|
||||
std::array<std::shared_ptr<SLE const>, maxCache> cache_;
|
||||
|
||||
std::optional<Bytes> data_;
|
||||
|
||||
public:
|
||||
std::expected<std::shared_ptr<SLE const>, HostFunctionError>
|
||||
getCurrentLedgerObj() const
|
||||
{
|
||||
if (!currentLedgerObj_)
|
||||
currentLedgerObj_ = ctx_.view().read(leKey_);
|
||||
if (*currentLedgerObj_)
|
||||
return *currentLedgerObj_;
|
||||
return std::unexpected(HostFunctionError::LedgerObjNotFound);
|
||||
}
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
normalizeCacheIndex(int32_t cacheIdx) const
|
||||
{
|
||||
--cacheIdx;
|
||||
if (cacheIdx < 0 || cacheIdx >= maxCache)
|
||||
return std::unexpected(HostFunctionError::SlotOutRange);
|
||||
if (!cache_[cacheIdx])
|
||||
return std::unexpected(HostFunctionError::EmptySlot);
|
||||
return cacheIdx;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void
|
||||
log(std::string_view const& msg, F&& dataFn) const
|
||||
{
|
||||
#ifdef DEBUG_OUTPUT
|
||||
auto& j = std::cerr;
|
||||
#else
|
||||
if (!getJournal().active(beast::Severity::Trace))
|
||||
return;
|
||||
auto j = getJournal().trace();
|
||||
#endif
|
||||
j << "WasmTrace[" << toShortString(leKey_.key) << "]: " << msg << " " << dataFn();
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
j << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
WasmHostFunctionsImpl(ApplyContext& ct, Keylet const& leKey)
|
||||
: HostFunctions(ct.journal), ctx_(ct), leKey_(leKey)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
checkSelf() const override
|
||||
{
|
||||
return !currentLedgerObj_ && !data_ &&
|
||||
std::ranges::none_of(cache_, [](auto const& p) { return !!p; });
|
||||
}
|
||||
|
||||
std::optional<Bytes> const&
|
||||
getData() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
std::expected<std::uint32_t, HostFunctionError>
|
||||
getLedgerSqn() const override;
|
||||
|
||||
std::expected<std::uint32_t, HostFunctionError>
|
||||
getParentLedgerTime() const override;
|
||||
|
||||
std::expected<Hash, HostFunctionError>
|
||||
getParentLedgerHash() const override;
|
||||
|
||||
std::expected<std::uint32_t, HostFunctionError>
|
||||
getBaseFee() const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(uint256 const& amendmentId) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
isAmendmentEnabled(std::string_view const& amendmentName) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
cacheLedgerObj(uint256 const& objId, int32_t cacheIdx) override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getTxField(SField const& fname) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjField(SField const& fname) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getLedgerObjField(int32_t cacheIdx, SField const& fname) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getTxNestedField(FieldLocator const& locator) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getCurrentLedgerObjNestedField(FieldLocator const& locator) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getLedgerObjNestedField(int32_t cacheIdx, FieldLocator const& locator) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
getTxArrayLen(SField const& fname) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjArrayLen(SField const& fname) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
getLedgerObjArrayLen(int32_t cacheIdx, SField const& fname) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
getTxNestedArrayLen(FieldLocator const& locator) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
getCurrentLedgerObjNestedArrayLen(FieldLocator const& locator) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
getLedgerObjNestedArrayLen(int32_t cacheIdx, FieldLocator const& locator) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
updateData(Slice const& data) override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
checkSignature(Slice const& message, Slice const& signature, Slice const& pubkey)
|
||||
const override;
|
||||
|
||||
std::expected<Hash, HostFunctionError>
|
||||
computeSha512HalfHash(Slice const& data) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
accountKeylet(AccountID const& account) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
ammKeylet(Asset const& issue1, Asset const& issue2) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
checkKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
credentialKeylet(AccountID const& subject, AccountID const& issuer, Slice const& credentialType)
|
||||
const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
didKeylet(AccountID const& account) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
delegateKeylet(AccountID const& account, AccountID const& authorize) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
depositPreauthKeylet(AccountID const& account, AccountID const& authorize) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
escrowKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
trustLineKeylet(AccountID const& account1, AccountID const& account2, Currency const& currency)
|
||||
const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
mptokenIssuanceKeylet(AccountID const& issuer, std::uint32_t seq) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
mptokenKeylet(MPTID const& mptid, AccountID const& holder) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
nftokenOfferKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
offerKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
oracleKeylet(AccountID const& account, std::uint32_t docId) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
paychannelKeylet(AccountID const& account, AccountID const& destination, std::uint32_t seq)
|
||||
const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
permissionedDomainKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
signerListKeylet(AccountID const& account) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
ticketKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
vaultKeylet(AccountID const& account, std::uint32_t seq) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getNFT(AccountID const& account, uint256 const& nftId) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
getNFTIssuer(uint256 const& nftId) const override;
|
||||
|
||||
std::expected<std::uint32_t, HostFunctionError>
|
||||
getNFTTaxon(uint256 const& nftId) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
getNFTFlags(uint256 const& nftId) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
getNFTTransferFee(uint256 const& nftId) const override;
|
||||
|
||||
std::expected<std::uint32_t, HostFunctionError>
|
||||
getNFTSequence(uint256 const& nftId) const override;
|
||||
|
||||
void
|
||||
trace(std::string_view const& msg, std::string_view const& data) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatFromInt(int64_t x, int32_t mode) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatFromUint(uint64_t x, int32_t mode) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatFromSTAmount(STAmount const& x, int32_t mode) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatFromSTNumber(STNumber const& x, int32_t mode) const override;
|
||||
|
||||
std::expected<int64_t, HostFunctionError>
|
||||
floatToInt(Slice const& x, int32_t mode) const override;
|
||||
|
||||
std::expected<FloatPair, HostFunctionError>
|
||||
floatToMantExp(Slice const& x) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatFromMantExp(int64_t mantissa, int32_t exponent, int32_t mode) const override;
|
||||
|
||||
std::expected<int32_t, HostFunctionError>
|
||||
floatCompare(Slice const& x, Slice const& y) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatAdd(Slice const& x, Slice const& y, int32_t mode) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatSubtract(Slice const& x, Slice const& y, int32_t mode) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatMultiply(Slice const& x, Slice const& y, int32_t mode) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatDivide(Slice const& x, Slice const& y, int32_t mode) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatRoot(Slice const& x, int32_t n, int32_t mode) const override;
|
||||
|
||||
std::expected<Bytes, HostFunctionError>
|
||||
floatPower(Slice const& x, int32_t n, int32_t mode) const override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
315
include/xrpl/tx/wasm/HostFuncWrapper.h
Normal file
315
include/xrpl/tx/wasm/HostFuncWrapper.h
Normal file
@@ -0,0 +1,315 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
|
||||
#include <wasm.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
#define WASM_CB_PARAMS_LIST void *env, wasm_val_vec_t const *params, wasm_val_vec_t *results
|
||||
#define WASM_SECONDARY_CB_PARAMS_LIST \
|
||||
HostFunctions &hf, wasm_val_vec_t const *params, wasm_val_vec_t *results
|
||||
|
||||
wasm_trap_t* HostFuncMain_wrap(WASM_CB_PARAMS_LIST);
|
||||
|
||||
using getLedgerSqn_proto = int32_t(uint8_t*, int32_t);
|
||||
wasm_trap_t* getLedgerSqn_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getParentLedgerTime_proto = int32_t(uint8_t*, int32_t);
|
||||
wasm_trap_t* getParentLedgerTime_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getParentLedgerHash_proto = int32_t(uint8_t*, int32_t);
|
||||
wasm_trap_t* getParentLedgerHash_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getBaseFee_proto = int32_t(uint8_t*, int32_t);
|
||||
wasm_trap_t* getBaseFee_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using isAmendmentEnabled_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* isAmendmentEnabled_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using cacheLedgerObj_proto = int32_t(uint8_t const*, int32_t, int32_t);
|
||||
wasm_trap_t* cacheLedgerObj_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getTxField_proto = int32_t(int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getTxField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getCurrentLedgerObjField_proto = int32_t(int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getCurrentLedgerObjField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getLedgerObjField_proto = int32_t(int32_t, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getLedgerObjField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getTxNestedField_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getTxNestedField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getCurrentLedgerObjNestedField_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getCurrentLedgerObjNestedField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getLedgerObjNestedField_proto = int32_t(int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getLedgerObjNestedField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getTxArrayLen_proto = int32_t(int32_t);
|
||||
wasm_trap_t* getTxArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getCurrentLedgerObjArrayLen_proto = int32_t(int32_t);
|
||||
wasm_trap_t* getCurrentLedgerObjArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getLedgerObjArrayLen_proto = int32_t(int32_t, int32_t);
|
||||
wasm_trap_t* getLedgerObjArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getTxNestedArrayLen_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* getTxNestedArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getCurrentLedgerObjNestedArrayLen_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* getCurrentLedgerObjNestedArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getLedgerObjNestedArrayLen_proto = int32_t(int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* getLedgerObjNestedArrayLen_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using updateData_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* updateData_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using checkSignature_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* checkSignature_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using computeSha512HalfHash_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* computeSha512HalfHash_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using accountKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* accountKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using ammKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* ammKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using checkKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* checkKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using credentialKeylet_proto = int32_t(
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t);
|
||||
wasm_trap_t* credentialKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using delegateKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* delegateKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using depositPreauthKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* depositPreauthKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using didKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* didKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using escrowKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* escrowKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using trustLineKeylet_proto = int32_t(
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t);
|
||||
wasm_trap_t* trustLineKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using mptokenIssuanceKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* mptokenIssuanceKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using mptokenKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* mptokenKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using nftokenOfferKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* nftokenOfferKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using offerKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* offerKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using oracleKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* oracleKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using paychannelKeylet_proto = int32_t(
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t);
|
||||
wasm_trap_t* paychannelKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using permissionedDomainKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* permissionedDomainKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using signerListKeylet_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* signerListKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using ticketKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* ticketKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using vaultKeylet_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* vaultKeylet_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFT_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getNFT_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFTIssuer_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getNFTIssuer_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFTTaxon_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getNFTTaxon_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFTFlags_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* getNFTFlags_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFTTransferFee_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* getNFTTransferFee_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getNFTSequence_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getNFTSequence_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
// trace(msg_ptr, msg_len, data_type, data_ptr, data_len); data_type is a
|
||||
// TraceDataType.
|
||||
using trace_proto = void(uint8_t const*, int32_t, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* trace_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatFromInt_proto = int32_t(int64_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatFromInt_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatFromUint_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatFromUint_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatFromSTAmount_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatFromSTAmount_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatFromSTNumber_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatFromSTNumber_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatToInt_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatToInt_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatToMantExp_proto = int32_t(uint8_t const*, int32_t, uint8_t*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* floatToMantExp_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatFromMantExp_proto = int32_t(int64_t, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatFromMantExp_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatCompare_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* floatCompare_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatAdd_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatAdd_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatSubtract_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatSubtract_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatMultiply_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatMultiply_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatDivide_proto =
|
||||
int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatDivide_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatRoot_proto = int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatRoot_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using floatPower_proto = int32_t(uint8_t const*, int32_t, int32_t, uint8_t*, int32_t, int32_t);
|
||||
wasm_trap_t* floatPower_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
// Contract-specific host function wrappers
|
||||
|
||||
using instanceParam_proto = int32_t(int32_t, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* instanceParam_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using functionParam_proto = int32_t(int32_t, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* functionParam_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getDataObjectField_proto =
|
||||
int32_t(uint8_t*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getDataObjectField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getDataNestedObjectField_proto =
|
||||
int32_t(uint8_t*, int32_t, uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getDataNestedObjectField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using setDataObjectField_proto =
|
||||
int32_t(uint8_t*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* setDataObjectField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using setDataNestedObjectField_proto =
|
||||
int32_t(uint8_t*, int32_t, uint8_t const*, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* setDataNestedObjectField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getDataArrayElementField_proto =
|
||||
int32_t(uint8_t*, int32_t, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* getDataArrayElementField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using getDataNestedArrayElementField_proto = int32_t(
|
||||
uint8_t*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t);
|
||||
wasm_trap_t* getDataNestedArrayElementField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using setDataArrayElementField_proto =
|
||||
int32_t(uint8_t*, int32_t, int32_t, uint8_t const*, int32_t, uint8_t*, int32_t);
|
||||
wasm_trap_t* setDataArrayElementField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using setDataNestedArrayElementField_proto = int32_t(
|
||||
uint8_t*,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
int32_t,
|
||||
uint8_t const*,
|
||||
int32_t,
|
||||
uint8_t*,
|
||||
int32_t);
|
||||
wasm_trap_t* setDataNestedArrayElementField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using buildTxn_proto = int32_t(int32_t);
|
||||
wasm_trap_t* buildTxn_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using addTxnField_proto = int32_t(int32_t, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* addTxnField_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using emitBuiltTxn_proto = int32_t(int32_t);
|
||||
wasm_trap_t* emitBuiltTxn_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using emitTxn_proto = int32_t(uint8_t const*, int32_t);
|
||||
wasm_trap_t* emitTxn_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
using emitEvent_proto = int32_t(uint8_t const*, int32_t, uint8_t const*, int32_t);
|
||||
wasm_trap_t* emitEvent_wrap(WASM_SECONDARY_CB_PARAMS_LIST);
|
||||
|
||||
} // namespace xrpl
|
||||
189
include/xrpl/tx/wasm/README.md
Normal file
189
include/xrpl/tx/wasm/README.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# WASM Module for Programmable Escrows
|
||||
|
||||
This module provides WebAssembly (WASM) execution capabilities for programmable
|
||||
escrows on the XRP Ledger. When an escrow is finished, the WASM code runs to
|
||||
determine whether the escrow conditions are met, enabling custom programmable
|
||||
logic for escrow release conditions.
|
||||
|
||||
For the full specification, see
|
||||
[XLS-0102: WASM VM](https://xls.xrpl.org/xls/XLS-0102-wasm-vm.html).
|
||||
|
||||
## Architecture
|
||||
|
||||
The module follows a layered architecture:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ WasmEngine (WasmVM.h) │
|
||||
│ runEscrowWasm(), preflightEscrowWasm() │
|
||||
│ Host function registration │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ WasmiEngine (WasmiVM.h) │
|
||||
│ Low-level wasmi interpreter integration │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ HostFuncWrapper │ HostFuncImpl │
|
||||
│ C-style WASM bridges │ C++ implementations │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ HostFunc (Interface) │
|
||||
│ Abstract base class for host functions │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Key Components
|
||||
|
||||
- **`WasmVM.h` / `detail/WasmVM.cpp`** - High-level facade providing:
|
||||
- `WasmEngine` singleton that wraps the underlying WASM interpreter
|
||||
- `runEscrowWasm()` - Execute WASM code for escrow finish
|
||||
- `preflightEscrowWasm()` - Validate WASM code during preflight
|
||||
- `createWasmImport()` - Register all host functions
|
||||
|
||||
- **`WasmiVM.h` / `detail/WasmiVM.cpp`** - Low-level integration with the
|
||||
[wasmi](https://github.com/wasmi-labs/wasmi) WebAssembly interpreter:
|
||||
- `WasmiEngine` - Manages WASM modules, instances, and execution
|
||||
- Memory management and gas metering
|
||||
- Function invocation and result handling
|
||||
|
||||
- **`HostFunc.h`** - Abstract `HostFunctions` base class defining the interface
|
||||
for all callable host functions. Each method returns
|
||||
`std::expected<T, HostFunctionError>`.
|
||||
|
||||
- **`HostFuncImpl.h` / `detail/HostFuncImpl*.cpp`** - Concrete
|
||||
`WasmHostFunctionsImpl` class that implements host functions with access to
|
||||
`ApplyContext` for ledger state queries. Implementation split across files:
|
||||
- `HostFuncImpl.cpp` - Core utilities (updateData, checkSignature, etc.)
|
||||
- `HostFuncImplFloat.cpp` - Float/number arithmetic operations
|
||||
- `HostFuncImplGetter.cpp` - Field access (transaction, ledger objects)
|
||||
- `HostFuncImplKeylet.cpp` - Keylet construction functions
|
||||
- `HostFuncImplLedgerHeader.cpp` - Ledger header info access
|
||||
- `HostFuncImplNFT.cpp` - NFT-related queries
|
||||
- `HostFuncImplTrace.cpp` - Debugging/tracing functions
|
||||
|
||||
- **`HostFuncWrapper.h` / `detail/HostFuncWrapper.cpp`** - C-style wrapper
|
||||
functions that bridge WASM calls to C++ `HostFunctions` methods. Each host
|
||||
function has:
|
||||
- A `_proto` type alias defining the function signature
|
||||
- A `_wrap` function that extracts parameters and calls the implementation
|
||||
|
||||
- **`ParamsHelper.h`** - Utilities for WASM parameter handling:
|
||||
- `WASM_IMPORT_FUNC` / `WASM_IMPORT_FUNC2` macros for registration
|
||||
- `wasmParams()` helper for building parameter vectors
|
||||
- Type conversion between WASM and C++ types
|
||||
|
||||
## Host Functions
|
||||
|
||||
Host functions allow WASM code to interact with the XRP Ledger. They are
|
||||
organized into categories:
|
||||
|
||||
- **Ledger Information** - Access ledger sequence, timestamps, hashes, fees
|
||||
- **Transaction & Ledger Object Access** - Read fields from the transaction
|
||||
and ledger objects (including the current escrow object)
|
||||
- **Keylet Construction** - Build keylets to look up various ledger object types
|
||||
- **Cryptography** - Signature verification and hashing
|
||||
- **Float Arithmetic** - Mathematical operations for amount calculations
|
||||
- **NFT Operations** - Query NFT properties
|
||||
- **Tracing/Debugging** - Log messages for debugging
|
||||
|
||||
For the complete list of available host functions, their WASM names, and gas
|
||||
costs, see the [XLS-0102 specification](https://xls.xrpl.org/xls/XLS-0102-wasm-vm.html)
|
||||
or `detail/WasmVM.cpp` where they are registered via `WASM_IMPORT_FUNC2` macros.
|
||||
For method signatures, see `HostFunc.h`.
|
||||
|
||||
## Gas Model
|
||||
|
||||
Each host function has an associated gas cost. The gas cost is specified when
|
||||
registering the function in `detail/WasmVM.cpp`:
|
||||
|
||||
```cpp
|
||||
WASM_IMPORT_FUNC2(i, getLedgerSqn, "get_ledger_sqn", hfs, 60);
|
||||
// ^^ gas cost
|
||||
```
|
||||
|
||||
WASM execution is metered, and if the gas limit is exceeded, execution fails.
|
||||
|
||||
## Entry Point
|
||||
|
||||
The WASM module must export a function with the name defined by
|
||||
`escrowFunctionName` (currently `"escrow_finish"`). This function:
|
||||
|
||||
- Takes no parameters (or parameters passed via host function calls)
|
||||
- Returns an `int32_t`:
|
||||
- `1` (or positive): Escrow conditions are met, allow finish
|
||||
- `0` (or negative): Escrow conditions are not met, reject finish
|
||||
|
||||
## Adding a New Host Function
|
||||
|
||||
To add a new host function, follow these steps:
|
||||
|
||||
### 1. Add to HostFunc.h (Base Class)
|
||||
|
||||
Add a virtual method declaration with a default implementation that returns an
|
||||
error:
|
||||
|
||||
```cpp
|
||||
virtual std::expected<ReturnType, HostFunctionError>
|
||||
myNewFunction(ParamType1 param1, ParamType2 param2)
|
||||
{
|
||||
return std::unexpected(HostFunctionError::INTERNAL);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Add to HostFuncImpl.h (Declaration)
|
||||
|
||||
Add the method override declaration in `WasmHostFunctionsImpl`:
|
||||
|
||||
```cpp
|
||||
std::expected<ReturnType, HostFunctionError>
|
||||
myNewFunction(ParamType1 param1, ParamType2 param2) override;
|
||||
```
|
||||
|
||||
### 3. Implement in detail/HostFuncImpl\*.cpp
|
||||
|
||||
Add the implementation in the appropriate file:
|
||||
|
||||
```cpp
|
||||
std::expected<ReturnType, HostFunctionError>
|
||||
WasmHostFunctionsImpl::myNewFunction(ParamType1 param1, ParamType2 param2)
|
||||
{
|
||||
// Implementation using ctx (ApplyContext) for ledger access
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Add Wrapper to HostFuncWrapper.h
|
||||
|
||||
Add the prototype and wrapper declaration:
|
||||
|
||||
```cpp
|
||||
using myNewFunction_proto = int32_t(uint8_t const*, int32_t, ...);
|
||||
wasm_trap_t*
|
||||
myNewFunction_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results);
|
||||
```
|
||||
|
||||
### 5. Implement Wrapper in detail/HostFuncWrapper.cpp
|
||||
|
||||
Implement the C-style wrapper that bridges WASM to C++:
|
||||
|
||||
```cpp
|
||||
wasm_trap_t*
|
||||
myNewFunction_wrap(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
|
||||
{
|
||||
// Extract parameters from params
|
||||
// Call hfs->myNewFunction(...)
|
||||
// Set results and return
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Register in WasmVM.cpp
|
||||
|
||||
Add the function registration in `setCommonHostFunctions()` or
|
||||
`createWasmImport()`:
|
||||
|
||||
```cpp
|
||||
WASM_IMPORT_FUNC2(i, myNewFunction, "my_new_function", hfs, 100);
|
||||
// ^^ WASM name ^^ gas cost
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> New host functions MUST be amendment-gated in `WasmVM.cpp`.
|
||||
> Wrap the registration in an amendment check to ensure the function is only
|
||||
> available after the corresponding amendment is enabled on the network.
|
||||
256
include/xrpl/tx/wasm/WasmCommon.h
Normal file
256
include/xrpl/tx/wasm/WasmCommon.h
Normal file
@@ -0,0 +1,256 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
|
||||
#include <bit>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
using Bytes = std::vector<std::uint8_t>;
|
||||
using Hash = xrpl::uint256;
|
||||
using FloatPair = std::pair<int64_t, int32_t>;
|
||||
|
||||
// Error signals that cross the wasm boundary as trap messages (the C API has no
|
||||
// trap code). WasmiEngine::call maps them to TER: hfErrInternal -> tecINTERNAL,
|
||||
// hfErrOutOfGas / wasmi's OutOfFuel -> tecOUT_OF_GAS, anything else ->
|
||||
// tecFAILED_PROCESSING.
|
||||
//
|
||||
// Matched as substrings, not by equality: the C API returns the Rust Debug form
|
||||
// of the error, e.g. `Error { kind: Message("HfInternal") }` or
|
||||
// `Error { kind: TrapCode(OutOfFuel) }`.
|
||||
std::string_view inline constexpr hfErrInternal = "HfInternal";
|
||||
std::string_view inline constexpr hfErrOutOfGas = "HfOutOfGas";
|
||||
std::string_view inline constexpr wasmiTrapOutOfFuel = "OutOfFuel";
|
||||
|
||||
// Guest ABI, mirrored in the wasm stdlib: append only, never renumber. Starts at
|
||||
// 1 so a zeroed data_type is rejected rather than treated as Int64.
|
||||
enum class TraceDataType : std::int32_t {
|
||||
Int64 = 1,
|
||||
Uint64,
|
||||
Xfloat,
|
||||
Account,
|
||||
Amount,
|
||||
AsHex, // raw bytes, hex-encoded by the host before printing
|
||||
AsText, // bytes printed verbatim as text
|
||||
};
|
||||
|
||||
enum class HostFunctionError : int32_t {
|
||||
Success = 0,
|
||||
Unimplemented = -1,
|
||||
FieldNotFound = -2,
|
||||
BufferTooSmall = -3,
|
||||
NoArray = -4,
|
||||
NotLeafField = -5,
|
||||
LocatorMalformed = -6,
|
||||
SlotOutRange = -7,
|
||||
SlotsFull = -8,
|
||||
EmptySlot = -9,
|
||||
LedgerObjNotFound = -10,
|
||||
OutOfTransferLimit = -11,
|
||||
DataFieldTooLarge = -12,
|
||||
PointerOutOfBounds = -13,
|
||||
NoMemExported = -14,
|
||||
InvalidParams = -15,
|
||||
InvalidAccount = -16,
|
||||
InvalidField = -17,
|
||||
IndexOutOfBounds = -18,
|
||||
FloatInputMalformed = -19,
|
||||
FloatComputationError = -20,
|
||||
SubmitTxnFailure = -21,
|
||||
InvalidState = -22,
|
||||
};
|
||||
|
||||
enum class WasmTypes { WtI32, WtI64 };
|
||||
|
||||
struct Wmem
|
||||
{
|
||||
std::uint8_t* p = nullptr;
|
||||
std::size_t s = 0;
|
||||
|
||||
Wmem() = default;
|
||||
Wmem(void* ptr, std::size_t size) : p(reinterpret_cast<std::uint8_t*>(ptr)), s(size)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct WasmResult
|
||||
{
|
||||
T result;
|
||||
int64_t cost;
|
||||
};
|
||||
using EscrowResult = WasmResult<int32_t>;
|
||||
|
||||
// Engine error when wasm does not run to completion. `cost` is the gas consumed
|
||||
// when meaningful (tecOUT_OF_GAS / tecFAILED_PROCESSING; caller writes it to tx
|
||||
// metadata); std::nullopt for tecINTERNAL and malformed input (no gas reported).
|
||||
struct WasmTER
|
||||
{
|
||||
TER ter;
|
||||
std::optional<int64_t> cost;
|
||||
};
|
||||
|
||||
class FieldLocator
|
||||
{
|
||||
int32_t const* ptr_ = nullptr;
|
||||
uint32_t size_ = 0;
|
||||
std::vector<int32_t> buf_;
|
||||
|
||||
public:
|
||||
FieldLocator(std::vector<int32_t>&& buf)
|
||||
: ptr_(&buf[0]), size_(buf.size()), buf_(std::move(buf))
|
||||
{
|
||||
}
|
||||
|
||||
FieldLocator(int32_t const* ptr, uint32_t const size) : ptr_(ptr), size_(size)
|
||||
{
|
||||
}
|
||||
|
||||
FieldLocator(FieldLocator const&) = delete;
|
||||
FieldLocator&
|
||||
operator=(FieldLocator const&) = delete;
|
||||
FieldLocator(FieldLocator&&) = default;
|
||||
FieldLocator&
|
||||
operator=(FieldLocator&&) = default;
|
||||
|
||||
int32_t
|
||||
operator[](unsigned i) const
|
||||
{
|
||||
if (i >= size_)
|
||||
Throw<std::runtime_error>("index out of bounds");
|
||||
return ptr_[i];
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t
|
||||
size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
[[nodiscard]] int32_t const*
|
||||
data() const
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
empty() const
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
};
|
||||
|
||||
class WasmRuntimeWrapper
|
||||
{
|
||||
public:
|
||||
virtual ~WasmRuntimeWrapper() = default;
|
||||
|
||||
virtual Wmem
|
||||
getMem() = 0;
|
||||
|
||||
virtual std::int64_t
|
||||
getGas() = 0;
|
||||
|
||||
virtual std::int64_t
|
||||
setGas(std::int64_t gas) = 0;
|
||||
|
||||
virtual std::int64_t
|
||||
getTransferLimit() = 0;
|
||||
|
||||
virtual std::int64_t
|
||||
setTransferLimit(std::int64_t transferLimit) = 0;
|
||||
};
|
||||
using RTOptRef = std::optional<std::reference_wrapper<WasmRuntimeWrapper>>;
|
||||
|
||||
struct WasmParam
|
||||
{
|
||||
// We are not supporting float/double
|
||||
|
||||
WasmTypes type = WasmTypes::WtI32;
|
||||
union
|
||||
{
|
||||
std::int32_t i32;
|
||||
std::int64_t i64 = 0;
|
||||
} of;
|
||||
};
|
||||
|
||||
template <class... Types>
|
||||
inline void
|
||||
wasmParamsHlp(std::vector<WasmParam>& v, std::int32_t p, Types&&... args)
|
||||
{
|
||||
v.push_back({.type = WasmTypes::WtI32, .of = {.i32 = p}});
|
||||
wasmParamsHlp(v, std::forward<Types>(args)...);
|
||||
}
|
||||
|
||||
template <class... Types>
|
||||
inline void
|
||||
wasmParamsHlp(std::vector<WasmParam>& v, std::int64_t p, Types&&... args)
|
||||
{
|
||||
v.push_back({.type = WasmTypes::WtI64, .of = {.i64 = p}});
|
||||
wasmParamsHlp(v, std::forward<Types>(args)...);
|
||||
}
|
||||
|
||||
inline void
|
||||
wasmParamsHlp(std::vector<WasmParam>& v)
|
||||
{
|
||||
}
|
||||
|
||||
template <class... Types>
|
||||
inline std::vector<WasmParam>
|
||||
wasmParams(Types&&... args)
|
||||
{
|
||||
std::vector<WasmParam> v;
|
||||
v.reserve(sizeof...(args));
|
||||
wasmParamsHlp(v, std::forward<Types>(args)...);
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T, size_t Size = sizeof(T)>
|
||||
constexpr T
|
||||
adjustWasmEndianessHlp(T x)
|
||||
{
|
||||
static_assert(std::is_integral_v<T>, "Only integral types");
|
||||
if constexpr (Size > 1)
|
||||
{
|
||||
using U = std::make_unsigned_t<T>;
|
||||
U u = static_cast<U>(x);
|
||||
U const low = (u & 0xFF) << ((Size - 1) << 3);
|
||||
u = adjustWasmEndianessHlp<U, Size - 1>(u >> 8);
|
||||
return static_cast<T>(low | u);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
template <typename T, size_t Size = sizeof(T)>
|
||||
constexpr T
|
||||
adjustWasmEndianess(T x)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
static_assert(std::is_integral_v<T>, "Only integral types");
|
||||
if constexpr (std::endian::native == std::endian::big)
|
||||
{
|
||||
return adjustWasmEndianessHlp(x);
|
||||
}
|
||||
return x;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
constexpr int32_t
|
||||
hfErrorToInt(HostFunctionError e)
|
||||
{
|
||||
return static_cast<int32_t>(e);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
126
include/xrpl/tx/wasm/WasmImportsHelper.h
Normal file
126
include/xrpl/tx/wasm/WasmImportsHelper.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
|
||||
#include <boost/function_types/function_arity.hpp>
|
||||
#include <boost/function_types/parameter_types.hpp>
|
||||
#include <boost/function_types/result_type.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
|
||||
#include <wasm.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace bft = boost::function_types;
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
using wasmSecondaryCbFuncType =
|
||||
wasm_trap_t*(HostFunctions&, wasm_val_vec_t const*, wasm_val_vec_t*);
|
||||
|
||||
struct WasmImportFunc
|
||||
{
|
||||
std::string_view name;
|
||||
std::optional<WasmTypes> result;
|
||||
std::vector<WasmTypes> params;
|
||||
|
||||
wasmSecondaryCbFuncType* wrap = nullptr;
|
||||
uint32_t gas = 0;
|
||||
};
|
||||
|
||||
using WasmUserData = std::pair<HFRef, WasmImportFunc>;
|
||||
// string - import function name
|
||||
using ImportVec = std::unordered_map<std::string_view, WasmUserData>;
|
||||
|
||||
template <int N, int C, typename Mpl>
|
||||
void
|
||||
WasmImpArgs(WasmImportFunc& e)
|
||||
{
|
||||
if constexpr (N < C)
|
||||
{
|
||||
using at = boost::mpl::at_c<Mpl, N>::type;
|
||||
if constexpr (std::is_pointer_v<at> || std::is_same_v<at, std::int32_t>)
|
||||
{
|
||||
e.params.push_back(WasmTypes::WtI32);
|
||||
}
|
||||
else if constexpr (std::is_same_v<at, std::int64_t>)
|
||||
{
|
||||
e.params.push_back(WasmTypes::WtI64);
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(std::is_pointer_v<at>, "Unsupported argument type");
|
||||
}
|
||||
|
||||
return WasmImpArgs<N + 1, C, Mpl>(e);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename>
|
||||
inline constexpr bool wasmDependentFalse = false;
|
||||
|
||||
template <typename Rt>
|
||||
void
|
||||
WasmImpRet(WasmImportFunc& e)
|
||||
{
|
||||
if constexpr (std::is_pointer_v<Rt> || std::is_same_v<Rt, std::int32_t>)
|
||||
{
|
||||
e.result = WasmTypes::WtI32;
|
||||
}
|
||||
else if constexpr (std::is_same_v<Rt, std::int64_t>)
|
||||
{
|
||||
e.result = WasmTypes::WtI64;
|
||||
}
|
||||
else if constexpr (std::is_void_v<Rt>)
|
||||
{
|
||||
e.result.reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(wasmDependentFalse<Rt>, "Unsupported return type");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void
|
||||
WasmImpFuncHelper(WasmImportFunc& e)
|
||||
{
|
||||
using rt = bft::result_type<F>::type;
|
||||
using pt = bft::parameter_types<F>::type;
|
||||
// typename boost::mpl::at_c<mpl, N>::type
|
||||
|
||||
WasmImpRet<rt>(e);
|
||||
WasmImpArgs<0, bft::function_arity<F>::value, pt>(e);
|
||||
// WasmImpWrap(e, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// imp_name - string literal, must have static lifetime
|
||||
template <typename F>
|
||||
void
|
||||
WasmImpFunc(
|
||||
ImportVec& v,
|
||||
std::string_view impName,
|
||||
wasmSecondaryCbFuncType* fWrap,
|
||||
HostFunctions& hf,
|
||||
uint32_t gas = 0)
|
||||
{
|
||||
WasmImportFunc e;
|
||||
e.name = impName;
|
||||
e.wrap = fWrap;
|
||||
e.gas = gas;
|
||||
WasmImpFuncHelper<F>(e);
|
||||
v.emplace(impName, std::make_pair(HFRef(hf), std::move(e)));
|
||||
}
|
||||
|
||||
#define WASM_IMPORT_FUNC(v, f, ...) WasmImpFunc<f##_proto>(v, #f, &f##_wrap, ##__VA_ARGS__)
|
||||
|
||||
// n - string literal name, must have static lifetime
|
||||
#define WASM_IMPORT_FUNC2(v, f, n, ...) WasmImpFunc<f##_proto>(v, n, &f##_wrap, ##__VA_ARGS__)
|
||||
|
||||
} // namespace xrpl
|
||||
97
include/xrpl/tx/wasm/WasmVM.h
Normal file
97
include/xrpl/tx/wasm/WasmVM.h
Normal file
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
#include <xrpl/tx/wasm/WasmImportsHelper.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
std::string_view inline constexpr wEnv = "env";
|
||||
std::string_view inline constexpr wHostLib = "host_lib";
|
||||
std::string_view inline constexpr wMem = "memory";
|
||||
std::string_view inline constexpr wStore = "store";
|
||||
std::string_view inline constexpr wLoad = "load";
|
||||
std::string_view inline constexpr wSize = "size";
|
||||
std::string_view inline constexpr wAlloc = "allocate";
|
||||
std::string_view inline constexpr wDealloc = "deallocate";
|
||||
std::string_view inline constexpr wProcExit = "proc_exit";
|
||||
|
||||
std::string_view inline constexpr escrowFunctionName = "escrow_finish";
|
||||
|
||||
uint32_t inline constexpr maxPages = 128; // 8MB = 64KB*128
|
||||
|
||||
class WasmiEngine;
|
||||
|
||||
class WasmEngine
|
||||
{
|
||||
std::unique_ptr<WasmiEngine> const impl_;
|
||||
|
||||
WasmEngine();
|
||||
|
||||
public:
|
||||
WasmEngine(WasmEngine const&) = delete;
|
||||
WasmEngine(WasmEngine&&) = delete;
|
||||
WasmEngine&
|
||||
operator=(WasmEngine const&) = delete;
|
||||
WasmEngine&
|
||||
operator=(WasmEngine&&) = delete;
|
||||
|
||||
static WasmEngine&
|
||||
instance();
|
||||
|
||||
std::expected<WasmResult<int32_t>, WasmTER>
|
||||
run(Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gasLimit,
|
||||
std::string_view funcName = {},
|
||||
std::vector<WasmParam> const& params = {},
|
||||
ImportVec const& imports = {},
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
NotTEC
|
||||
check(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params = {},
|
||||
ImportVec const& imports = {},
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
// Host functions helper functionality
|
||||
void*
|
||||
newTrap(std::string const& txt = std::string());
|
||||
|
||||
[[nodiscard]] beast::Journal
|
||||
getJournal() const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ImportVec
|
||||
createWasmImport(HostFunctions& hfs);
|
||||
|
||||
std::expected<EscrowResult, WasmTER>
|
||||
runEscrowWasm(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gasLimit,
|
||||
std::string_view funcName = escrowFunctionName,
|
||||
std::vector<WasmParam> const& params = {});
|
||||
|
||||
NotTEC
|
||||
preflightEscrowWasm(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName = escrowFunctionName,
|
||||
std::vector<WasmParam> const& params = {});
|
||||
|
||||
} // namespace xrpl
|
||||
462
include/xrpl/tx/wasm/WasmiVM.h
Normal file
462
include/xrpl/tx/wasm/WasmiVM.h
Normal file
@@ -0,0 +1,462 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
#include <xrpl/tx/wasm/WasmCommon.h>
|
||||
#include <xrpl/tx/wasm/WasmImportsHelper.h>
|
||||
#include <xrpl/tx/wasm/WasmVM.h>
|
||||
|
||||
#include <wasm.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <class T, void (*Create)(T*, size_t), void (*Destroy)(T*)>
|
||||
class WasmVec
|
||||
{
|
||||
using TD = std::remove_pointer_t<decltype(T::data)>;
|
||||
T vec_;
|
||||
|
||||
public:
|
||||
WasmVec(size_t s = 0) : vec_ WASM_EMPTY_VEC
|
||||
{
|
||||
if (s > 0)
|
||||
Create(&vec_, s); // zeroes memory
|
||||
}
|
||||
|
||||
~WasmVec()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
WasmVec(WasmVec const&) = delete;
|
||||
WasmVec&
|
||||
operator=(WasmVec const&) = delete;
|
||||
|
||||
WasmVec(WasmVec&& other) noexcept : vec_ WASM_EMPTY_VEC
|
||||
{
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
WasmVec&
|
||||
operator=(WasmVec&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
clear();
|
||||
vec_ = other.vec_;
|
||||
other.vec_ = WASM_EMPTY_VEC;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
Destroy(&vec_); // call destructor for every elements too
|
||||
vec_ = WASM_EMPTY_VEC;
|
||||
}
|
||||
|
||||
T
|
||||
release()
|
||||
{
|
||||
T result = vec_;
|
||||
vec_ = WASM_EMPTY_VEC;
|
||||
return result;
|
||||
}
|
||||
|
||||
T*
|
||||
get()
|
||||
{
|
||||
return &vec_;
|
||||
}
|
||||
|
||||
[[nodiscard]] T const*
|
||||
get() const
|
||||
{
|
||||
return &vec_;
|
||||
}
|
||||
|
||||
TD&
|
||||
operator[](size_t i)
|
||||
{
|
||||
if (i >= vec_.size)
|
||||
Throw<std::runtime_error>("Out of bound");
|
||||
return vec_.data[i];
|
||||
}
|
||||
|
||||
TD const&
|
||||
operator[](size_t i) const
|
||||
{
|
||||
if (i >= vec_.size)
|
||||
Throw<std::runtime_error>("Out of bound");
|
||||
return vec_.data[i];
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t
|
||||
size() const
|
||||
{
|
||||
return vec_.size;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
empty() const
|
||||
{
|
||||
return vec_.size == 0u;
|
||||
}
|
||||
};
|
||||
|
||||
using WasmValtypeVec =
|
||||
WasmVec<wasm_valtype_vec_t, &wasm_valtype_vec_new_uninitialized, &wasm_valtype_vec_delete>;
|
||||
using WasmValVec = WasmVec<wasm_val_vec_t, &wasm_val_vec_new_uninitialized, &wasm_val_vec_delete>;
|
||||
using WasmExternVec =
|
||||
WasmVec<wasm_extern_vec_t, &wasm_extern_vec_new_uninitialized, &wasm_extern_vec_delete>;
|
||||
using WasmExporttypeVec = WasmVec<
|
||||
wasm_exporttype_vec_t,
|
||||
&wasm_exporttype_vec_new_uninitialized,
|
||||
&wasm_exporttype_vec_delete>;
|
||||
using WasmImporttypeVec = WasmVec<
|
||||
wasm_importtype_vec_t,
|
||||
&wasm_importtype_vec_new_uninitialized,
|
||||
&wasm_importtype_vec_delete>;
|
||||
|
||||
struct WasmiResult
|
||||
{
|
||||
WasmValVec r;
|
||||
// Set iff the call trapped. Holds the TER the trap was classified into
|
||||
// (tecINTERNAL / tecOUT_OF_GAS / tecFAILED_PROCESSING); see
|
||||
// WasmiEngine::call. std::nullopt means the call returned normally.
|
||||
std::optional<TER> ter;
|
||||
|
||||
WasmiResult(unsigned n = 0) : r(n)
|
||||
{
|
||||
}
|
||||
|
||||
WasmiResult() = delete;
|
||||
~WasmiResult() = default;
|
||||
WasmiResult(WasmiResult&& o) = default;
|
||||
WasmiResult&
|
||||
operator=(WasmiResult&& o) = default;
|
||||
};
|
||||
|
||||
using ModulePtr = std::unique_ptr<wasm_module_t, decltype(&wasm_module_delete)>;
|
||||
using InstancePtr = std::unique_ptr<wasm_instance_t, decltype(&wasm_instance_delete)>;
|
||||
using EnginePtr = std::unique_ptr<wasm_engine_t, decltype(&wasm_engine_delete)>;
|
||||
using StorePtr = std::unique_ptr<wasm_store_t, decltype(&wasm_store_delete)>;
|
||||
|
||||
using FuncInfo = std::pair<wasm_func_t const*, wasm_functype_t const*>;
|
||||
|
||||
class InstanceWrapper
|
||||
{
|
||||
wasm_store_t* store_ = nullptr;
|
||||
WasmExternVec exports_;
|
||||
mutable int memIdx_ = -1;
|
||||
InstancePtr instance_;
|
||||
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
|
||||
std::int64_t transferLimit_ = kWasmTransferLimit;
|
||||
|
||||
private:
|
||||
static InstancePtr
|
||||
init(
|
||||
StorePtr& s,
|
||||
ModulePtr& m,
|
||||
WasmExternVec& expt,
|
||||
WasmExternVec const& imports,
|
||||
beast::Journal j);
|
||||
|
||||
public:
|
||||
InstanceWrapper() : instance_(nullptr, &wasm_instance_delete) {};
|
||||
|
||||
InstanceWrapper(InstanceWrapper const&) = delete;
|
||||
|
||||
InstanceWrapper(InstanceWrapper&& o) : instance_(nullptr, &wasm_instance_delete)
|
||||
{
|
||||
*this = std::move(o); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
InstanceWrapper(StorePtr& s, ModulePtr& m, WasmExternVec const& imports, beast::Journal j)
|
||||
: store_(s.get()), instance_(init(s, m, exports_, imports, j)), j_(j)
|
||||
{
|
||||
}
|
||||
|
||||
InstanceWrapper&
|
||||
operator=(InstanceWrapper&& o);
|
||||
|
||||
InstanceWrapper&
|
||||
operator=(InstanceWrapper const&) = delete;
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return static_cast<bool>(instance_);
|
||||
}
|
||||
|
||||
FuncInfo
|
||||
getFunc(std::string_view funcName, WasmExporttypeVec const& exportTypes) const;
|
||||
|
||||
Wmem
|
||||
getMem() const;
|
||||
|
||||
std::int64_t
|
||||
getGas() const;
|
||||
|
||||
std::int64_t
|
||||
setGas(std::int64_t) const;
|
||||
|
||||
std::int64_t
|
||||
getTransferLimit() const;
|
||||
|
||||
std::int64_t
|
||||
setTransferLimit(std::int64_t);
|
||||
};
|
||||
|
||||
class ModuleWrapper
|
||||
{
|
||||
ModulePtr module_;
|
||||
InstanceWrapper instanceWrap_;
|
||||
WasmExporttypeVec exportTypes_;
|
||||
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
|
||||
|
||||
public:
|
||||
// LCOV_EXCL_START
|
||||
ModuleWrapper() : module_(nullptr, &wasm_module_delete)
|
||||
{
|
||||
}
|
||||
|
||||
ModuleWrapper(ModuleWrapper&& o) : module_(nullptr, &wasm_module_delete)
|
||||
{
|
||||
*this = std::move(o);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
ModuleWrapper&
|
||||
operator=(ModuleWrapper&& o);
|
||||
ModuleWrapper(
|
||||
StorePtr& s,
|
||||
Bytes const& wasmBin,
|
||||
bool instantiate,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j);
|
||||
~ModuleWrapper() = default;
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return instanceWrap_;
|
||||
}
|
||||
|
||||
FuncInfo
|
||||
getFunc(std::string_view funcName) const
|
||||
{
|
||||
return instanceWrap_.getFunc(funcName, exportTypes_);
|
||||
}
|
||||
|
||||
wasm_functype_t const*
|
||||
getFuncType(std::string_view funcName) const;
|
||||
|
||||
Wmem
|
||||
getMem() const
|
||||
{
|
||||
return instanceWrap_.getMem();
|
||||
}
|
||||
|
||||
InstanceWrapper&
|
||||
getInstance(int i = 0)
|
||||
{
|
||||
return instanceWrap_;
|
||||
}
|
||||
|
||||
InstanceWrapper const&
|
||||
getInstance(int i = 0) const
|
||||
{
|
||||
return instanceWrap_;
|
||||
}
|
||||
|
||||
int
|
||||
addInstance(StorePtr& s, WasmExternVec const& imports)
|
||||
{
|
||||
instanceWrap_ = {s, module_, imports, j_};
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
getGas() const
|
||||
{
|
||||
return instanceWrap_ ? instanceWrap_.getGas() : -1;
|
||||
}
|
||||
|
||||
private:
|
||||
static ModulePtr
|
||||
init(StorePtr& s, Bytes const& wasmBin, beast::Journal j);
|
||||
|
||||
WasmExternVec
|
||||
buildImports(StorePtr& s, ImportVec const& imports) const;
|
||||
};
|
||||
|
||||
class WasmiEngine
|
||||
{
|
||||
EnginePtr engine_;
|
||||
StorePtr store_;
|
||||
std::unique_ptr<ModuleWrapper> moduleWrap_;
|
||||
beast::Journal j_ = beast::Journal(beast::Journal::getNullSink());
|
||||
|
||||
std::mutex m_; // 1 instance mutex
|
||||
|
||||
public:
|
||||
WasmiEngine() : engine_(init()), store_(nullptr, &wasm_store_delete)
|
||||
{
|
||||
}
|
||||
|
||||
~WasmiEngine() = default;
|
||||
|
||||
static EnginePtr
|
||||
init();
|
||||
|
||||
std::expected<WasmResult<int32_t>, WasmTER>
|
||||
run(Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gas,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j);
|
||||
|
||||
NotTEC
|
||||
check(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j);
|
||||
|
||||
[[nodiscard]] std::int64_t
|
||||
getGas() const
|
||||
{
|
||||
return moduleWrap_ ? moduleWrap_->getGas() : -1; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Host functions helper functionality
|
||||
wasm_trap_t*
|
||||
newTrap(std::string const& msg);
|
||||
|
||||
// LCOV_EXCL_START
|
||||
[[nodiscard]] beast::Journal
|
||||
getJournal() const
|
||||
{
|
||||
return j_;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
private:
|
||||
[[nodiscard]] InstanceWrapper&
|
||||
getRT(int m = 0, int i = 0) const
|
||||
{
|
||||
if (!moduleWrap_)
|
||||
Throw<std::runtime_error>("no module");
|
||||
return moduleWrap_->getInstance(i);
|
||||
}
|
||||
|
||||
[[nodiscard]] Wmem
|
||||
getMem() const
|
||||
{
|
||||
return moduleWrap_ ? moduleWrap_->getMem() : Wmem();
|
||||
}
|
||||
|
||||
std::expected<WasmResult<int32_t>, WasmTER>
|
||||
runHlp(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
int64_t gas,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j);
|
||||
|
||||
NotTEC
|
||||
checkHlp(
|
||||
Bytes const& wasmCode,
|
||||
HostFunctions& hfs,
|
||||
std::string_view funcName,
|
||||
std::vector<WasmParam> const& params,
|
||||
ImportVec const& imports,
|
||||
beast::Journal j);
|
||||
|
||||
int
|
||||
addModule(Bytes const& wasmCode, bool instantiate, ImportVec const& imports, int64_t gas);
|
||||
void
|
||||
clearModules();
|
||||
|
||||
// int addInstance();
|
||||
|
||||
int32_t
|
||||
runFunc(std::string_view const funcName, int32_t p);
|
||||
|
||||
int32_t
|
||||
makeModule(Bytes const& wasmCode, WasmExternVec const& imports = {});
|
||||
|
||||
[[nodiscard]] FuncInfo
|
||||
getFunc(std::string_view funcName) const
|
||||
{
|
||||
return moduleWrap_->getFunc(funcName);
|
||||
}
|
||||
|
||||
static std::vector<wasm_val_t>
|
||||
convertParams(std::vector<WasmParam> const& params);
|
||||
|
||||
static int
|
||||
compareParamTypes(wasm_valtype_vec_t const* ftp, std::vector<wasm_val_t> const& p);
|
||||
|
||||
static void
|
||||
addParam(std::vector<wasm_val_t>& in, int32_t p);
|
||||
static void
|
||||
addParam(std::vector<wasm_val_t>& in, int64_t p);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(std::string_view func, Types&&... args);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(FuncInfo const& f, Types&&... args);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(FuncInfo const& f, std::vector<wasm_val_t>& in);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(FuncInfo const& f, std::vector<wasm_val_t>& in, std::int32_t p, Types&&... args);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(FuncInfo const& f, std::vector<wasm_val_t>& in, std::int64_t p, Types&&... args);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(
|
||||
FuncInfo const& f,
|
||||
std::vector<wasm_val_t>& in,
|
||||
uint8_t const* d,
|
||||
int32_t sz,
|
||||
Types&&... args);
|
||||
|
||||
template <int NR, class... Types>
|
||||
inline WasmiResult
|
||||
call(FuncInfo const& f, std::vector<wasm_val_t>& in, Bytes const& p, Types&&... args);
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -113,6 +113,8 @@ ApplyStateTable::apply(
|
||||
TER ter,
|
||||
std::optional<STAmount> const& deliver,
|
||||
std::optional<uint256 const> const& parentBatchId,
|
||||
std::optional<std::uint32_t> const& gasUsed,
|
||||
std::optional<std::int32_t> const& vmReturnCode,
|
||||
bool isDryRun,
|
||||
beast::Journal j)
|
||||
{
|
||||
@@ -127,6 +129,8 @@ ApplyStateTable::apply(
|
||||
|
||||
meta.setDeliveredAmount(deliver);
|
||||
meta.setParentBatchID(parentBatchId);
|
||||
meta.setGasUsed(gasUsed);
|
||||
meta.setVMReturnCode(vmReturnCode);
|
||||
|
||||
Mods newMod;
|
||||
for (auto& item : items_)
|
||||
|
||||
@@ -30,7 +30,7 @@ ApplyViewImpl::apply(
|
||||
bool isDryRun,
|
||||
beast::Journal j)
|
||||
{
|
||||
return items_.apply(to, tx, ter, deliver_, parentBatchId, isDryRun, j);
|
||||
return items_.apply(to, tx, ter, deliver_, parentBatchId, gasUsed_, vmReturnCode_, isDryRun, j);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
|
||||
@@ -198,6 +198,12 @@ Ledger::Ledger(
|
||||
sle->at(sfReserveIncrement) = *f;
|
||||
sle->at(sfReferenceFeeUnits) = kFeeUnitsDeprecated;
|
||||
}
|
||||
if (std::ranges::find(amendments, featureSmartEscrow) != amendments.end())
|
||||
{
|
||||
sle->at(sfGasLimit) = fees.gasLimit;
|
||||
sle->at(sfBytecodeSizeLimit) = fees.bytecodeSizeLimit;
|
||||
sle->at(sfGasPrice) = fees.gasPrice;
|
||||
}
|
||||
rawInsert(sle);
|
||||
}
|
||||
|
||||
@@ -564,6 +570,7 @@ Ledger::setup()
|
||||
{
|
||||
bool oldFees = false;
|
||||
bool newFees = false;
|
||||
bool extensionFees = false;
|
||||
{
|
||||
auto const baseFee = sle->at(~sfBaseFee);
|
||||
auto const reserveBase = sle->at(~sfReserveBase);
|
||||
@@ -580,6 +587,7 @@ Ledger::setup()
|
||||
auto const baseFeeXRP = sle->at(~sfBaseFeeDrops);
|
||||
auto const reserveBaseXRP = sle->at(~sfReserveBaseDrops);
|
||||
auto const reserveIncrementXRP = sle->at(~sfReserveIncrementDrops);
|
||||
|
||||
auto assign = [&ret](XRPAmount& dest, std::optional<STAmount> const& src) {
|
||||
if (src)
|
||||
{
|
||||
@@ -598,6 +606,22 @@ Ledger::setup()
|
||||
assign(fees_.increment, reserveIncrementXRP);
|
||||
newFees = baseFeeXRP || reserveBaseXRP || reserveIncrementXRP;
|
||||
}
|
||||
{
|
||||
auto const gasLimit = sle->at(~sfGasLimit);
|
||||
auto const bytecodeSizeLimit = sle->at(~sfBytecodeSizeLimit);
|
||||
auto const gasPrice = sle->at(~sfGasPrice);
|
||||
|
||||
auto assign = [](std::uint32_t& dest, std::optional<std::uint32_t> const& src) {
|
||||
if (src)
|
||||
{
|
||||
dest = src.value();
|
||||
}
|
||||
};
|
||||
assign(fees_.gasLimit, gasLimit);
|
||||
assign(fees_.bytecodeSizeLimit, bytecodeSizeLimit);
|
||||
assign(fees_.gasPrice, gasPrice);
|
||||
extensionFees = gasLimit || bytecodeSizeLimit || gasPrice;
|
||||
}
|
||||
if (oldFees && newFees)
|
||||
{
|
||||
// Should be all of one or the other, but not both
|
||||
@@ -608,6 +632,12 @@ Ledger::setup()
|
||||
// Can't populate the new fees before the amendment is enabled
|
||||
ret = false;
|
||||
}
|
||||
if (!rules_.enabled(featureSmartEscrow) && extensionFees)
|
||||
{
|
||||
// Can't populate the extension fees before the amendment is
|
||||
// enabled
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SHAMapMissingNode const&)
|
||||
|
||||
@@ -484,6 +484,271 @@ doWithdraw(
|
||||
ctx.view, sourceAcct, dstAcct, amount, j, *sponsorSle, WaiveTransferFee::Yes);
|
||||
}
|
||||
|
||||
static TER
|
||||
canTransferIOU(
|
||||
ReadView const& view,
|
||||
AccountID const& sender,
|
||||
AccountID const& receiver,
|
||||
STAmount const& amount,
|
||||
beast::Journal j,
|
||||
SendIssuerHandling issuerHandling,
|
||||
SendEscrowHandling escrowHandling,
|
||||
SendAuthHandling authHandling,
|
||||
SendFreezeHandling freezeHandling,
|
||||
SendTransferHandling transferHandling,
|
||||
SendBalanceHandling balanceHandling)
|
||||
{
|
||||
AccountID const issuer = amount.getIssuer();
|
||||
// If the issuer is the same as the sender
|
||||
if (issuerHandling == SendIssuerHandling::ihSENDER_NOT_ALLOWED && issuer == sender)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the issuer is the same as the receiver
|
||||
if (issuerHandling == SendIssuerHandling::ihRECEIVER_NOT_ALLOWED && issuer == receiver)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the lsfAllowTrustLineLocking is not enabled
|
||||
auto const sleIssuer = view.read(keylet::account(issuer));
|
||||
if (!sleIssuer)
|
||||
return tecNO_ISSUER;
|
||||
|
||||
if (issuerHandling != SendIssuerHandling::ihSENDER_NOT_ALLOWED &&
|
||||
issuerHandling != SendIssuerHandling::ihRECEIVER_NOT_ALLOWED &&
|
||||
!sleIssuer->isFlag(lsfDefaultRipple))
|
||||
return terNO_RIPPLE;
|
||||
|
||||
if (escrowHandling == SendEscrowHandling::ehCHECK &&
|
||||
!sleIssuer->isFlag(lsfAllowTrustLineLocking))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the sender does not have a trustline to the issuer
|
||||
auto const sleRippleState =
|
||||
view.read(keylet::trustLine(sender, issuer, amount.get<Issue>().currency));
|
||||
|
||||
if (!sleRippleState)
|
||||
return tecNO_LINE;
|
||||
|
||||
STAmount const balance = (*sleRippleState)[sfBalance];
|
||||
|
||||
// If balance is positive, issuer must have higher address than sender
|
||||
if (balance > beast::kZero && issuer < sender)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
// If balance is negative, issuer must have lower address than sender
|
||||
if (balance < beast::kZero && issuer > sender)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
// // If the account trustline has no-ripple set for the issuer
|
||||
// if (auto const ter = requireNoRipple(ctx.view, amount.issue(), account);
|
||||
// ter != tesSUCCESS)
|
||||
// return ter;
|
||||
|
||||
// // If the dest trustline has no-ripple set for the issuer
|
||||
// if (auto const ter = requireNoRipple(ctx.view, amount.issue(), dest);
|
||||
// ter != tesSUCCESS)
|
||||
// return ter;
|
||||
|
||||
// If the issuer has requireAuth set, check if the sender is authorized
|
||||
if (authHandling == SendAuthHandling::ahCHECK_SENDER ||
|
||||
authHandling == SendAuthHandling::ahBOTH)
|
||||
{
|
||||
if (auto const ter = requireAuth(view, amount.asset(), sender); ter != tesSUCCESS)
|
||||
return ter;
|
||||
}
|
||||
|
||||
// If the issuer has requireAuth set, check if the receiver is authorized
|
||||
if (authHandling == SendAuthHandling::ahCHECK_RECEIVER ||
|
||||
authHandling == SendAuthHandling::ahBOTH)
|
||||
{
|
||||
if (auto const ter = requireAuth(view, amount.asset(), receiver); ter != tesSUCCESS)
|
||||
return ter;
|
||||
}
|
||||
|
||||
// If the issuer has frozen the sender
|
||||
if ((freezeHandling == SendFreezeHandling::fhCHECK_SENDER ||
|
||||
freezeHandling == SendFreezeHandling::fhBOTH) &&
|
||||
isFrozen(view, sender, amount.asset()))
|
||||
return tecFROZEN;
|
||||
|
||||
// If the issuer has frozen the receiver
|
||||
if ((freezeHandling == SendFreezeHandling::fhCHECK_RECEIVER ||
|
||||
freezeHandling == SendFreezeHandling::fhBOTH) &&
|
||||
isFrozen(view, receiver, amount.asset()))
|
||||
return tecFROZEN;
|
||||
|
||||
if (balanceHandling == SendBalanceHandling::bhIGNORE)
|
||||
return tesSUCCESS;
|
||||
|
||||
STAmount const spendableAmount = accountHolds(
|
||||
view,
|
||||
sender,
|
||||
amount.get<Issue>(),
|
||||
FreezeHandling::IgnoreFreeze, // already checked freeze above
|
||||
j);
|
||||
|
||||
// If the balance is less than or equal to 0
|
||||
if (spendableAmount <= beast::kZero)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
// If the spendable amount is less than the amount
|
||||
if (spendableAmount < amount)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
// If the amount is not addable to the balance
|
||||
if (!canAdd(spendableAmount, amount))
|
||||
return tecPRECISION_LOSS;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
static TER
|
||||
canTransferMPT(
|
||||
ReadView const& view,
|
||||
AccountID const& sender,
|
||||
AccountID const& receiver,
|
||||
STAmount const& amount,
|
||||
beast::Journal j,
|
||||
SendIssuerHandling issuerHandling,
|
||||
SendEscrowHandling escrowHandling,
|
||||
SendAuthHandling authHandling,
|
||||
SendFreezeHandling freezeHandling,
|
||||
SendTransferHandling transferHandling,
|
||||
SendBalanceHandling balanceHandling)
|
||||
{
|
||||
AccountID const issuer = amount.getIssuer();
|
||||
// If the issuer is the same as the sender
|
||||
if (issuerHandling == SendIssuerHandling::ihSENDER_NOT_ALLOWED && issuer == sender)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the issuer is the same as the receiver
|
||||
if (issuerHandling == SendIssuerHandling::ihRECEIVER_NOT_ALLOWED && issuer == receiver)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the mpt does not exist
|
||||
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
|
||||
auto const sleIssuance = view.read(issuanceKey);
|
||||
if (!sleIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
// If the lsfMPTCanEscrow is not enabled
|
||||
if (escrowHandling == SendEscrowHandling::ehCHECK && !sleIssuance->isFlag(lsfMPTCanEscrow))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the issuer is not the same as the issuer of the mpt
|
||||
if (sleIssuance->getAccountID(sfIssuer) != issuer)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
// If the sender does not have the mpt
|
||||
if (!view.exists(keylet::mptoken(issuanceKey.key, sender)))
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
auto const& mptIssue = amount.get<MPTIssue>();
|
||||
|
||||
// If the issuer has requireAuth set, check if the sender is authorized
|
||||
if (authHandling == SendAuthHandling::ahCHECK_SENDER ||
|
||||
authHandling == SendAuthHandling::ahBOTH)
|
||||
{
|
||||
if (auto const ter = requireAuth(view, mptIssue, sender, AuthType::WeakAuth);
|
||||
ter != tesSUCCESS)
|
||||
return ter;
|
||||
}
|
||||
|
||||
// If the issuer has requireAuth set, check if the receiver is authorized
|
||||
if (authHandling == SendAuthHandling::ahCHECK_RECEIVER ||
|
||||
authHandling == SendAuthHandling::ahBOTH)
|
||||
{
|
||||
if (auto const ter = requireAuth(view, mptIssue, receiver, AuthType::WeakAuth);
|
||||
ter != tesSUCCESS)
|
||||
return ter;
|
||||
}
|
||||
|
||||
// If the issuer has frozen the sender, return tecLOCKED
|
||||
if ((freezeHandling == SendFreezeHandling::fhCHECK_SENDER ||
|
||||
freezeHandling == SendFreezeHandling::fhBOTH) &&
|
||||
isFrozen(view, sender, mptIssue))
|
||||
return tecLOCKED;
|
||||
|
||||
// If the issuer has frozen the receiver, return tecLOCKED
|
||||
if ((freezeHandling == SendFreezeHandling::fhCHECK_RECEIVER ||
|
||||
freezeHandling == SendFreezeHandling::fhBOTH) &&
|
||||
isFrozen(view, receiver, mptIssue))
|
||||
return tecLOCKED;
|
||||
|
||||
// If the mpt cannot be transferred, return tecNO_AUTH
|
||||
if (transferHandling == SendTransferHandling::thCHECK)
|
||||
{
|
||||
if (auto const ter = canTransfer(view, mptIssue, sender, receiver); ter != tesSUCCESS)
|
||||
return ter;
|
||||
}
|
||||
|
||||
if (balanceHandling == SendBalanceHandling::bhIGNORE)
|
||||
return tesSUCCESS;
|
||||
|
||||
STAmount const spendableAmount = accountHolds(
|
||||
view,
|
||||
sender,
|
||||
amount.get<MPTIssue>(),
|
||||
FreezeHandling::IgnoreFreeze, // already checked freeze above
|
||||
AuthHandling::IgnoreAuth, // already checked auth above
|
||||
j);
|
||||
|
||||
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount <= beast::kZero)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
// If the spendable amount is less than the amount, return
|
||||
// tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount < amount)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
canTransferFT(
|
||||
ReadView const& view,
|
||||
AccountID const& sender,
|
||||
AccountID const& receiver,
|
||||
STAmount const& amount,
|
||||
beast::Journal j,
|
||||
SendIssuerHandling issuerHandling = SendIssuerHandling::ihIGNORE,
|
||||
SendEscrowHandling escrowHandling = SendEscrowHandling::ehIGNORE,
|
||||
SendAuthHandling authHandling = SendAuthHandling::ahBOTH,
|
||||
SendFreezeHandling freezeHandling = SendFreezeHandling::fhBOTH,
|
||||
SendTransferHandling transferHandling = SendTransferHandling::thIGNORE,
|
||||
SendBalanceHandling balanceHandling = SendBalanceHandling::bhCHECK)
|
||||
{
|
||||
return std::visit(
|
||||
[&]<ValidIssueType TIss>(TIss const& issue) -> TER {
|
||||
if constexpr (std::is_same_v<TIss, Issue>)
|
||||
return canTransferIOU(
|
||||
view,
|
||||
sender,
|
||||
receiver,
|
||||
amount,
|
||||
j,
|
||||
issuerHandling,
|
||||
escrowHandling,
|
||||
authHandling,
|
||||
freezeHandling,
|
||||
transferHandling,
|
||||
balanceHandling);
|
||||
else
|
||||
return canTransferMPT(
|
||||
view,
|
||||
sender,
|
||||
receiver,
|
||||
amount,
|
||||
j,
|
||||
issuerHandling,
|
||||
escrowHandling,
|
||||
authHandling,
|
||||
freezeHandling,
|
||||
transferHandling,
|
||||
balanceHandling);
|
||||
},
|
||||
amount.asset().value());
|
||||
}
|
||||
TER
|
||||
cleanupOnAccountDelete(
|
||||
ApplyView& view,
|
||||
|
||||
632
src/libxrpl/ledger/helpers/ContractUtils.cpp
Normal file
632
src/libxrpl/ledger/helpers/ContractUtils.cpp
Normal file
@@ -0,0 +1,632 @@
|
||||
#include <xrpl/ledger/helpers/ContractUtils.h>
|
||||
|
||||
#include <xrpl/ledger/View.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STArray.h>
|
||||
#include <xrpl/protocol/STJson.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/server/NetworkOPs.h>
|
||||
|
||||
namespace xrpl {
|
||||
namespace contract {
|
||||
|
||||
struct BlobHash
|
||||
{
|
||||
std::size_t
|
||||
operator()(Blob const& b) const noexcept
|
||||
{
|
||||
if (b.empty())
|
||||
return 0;
|
||||
return std::hash<std::string_view>{}(
|
||||
std::string_view(reinterpret_cast<char const*>(b.data()), b.size()));
|
||||
}
|
||||
};
|
||||
|
||||
int64_t
|
||||
contractCreateFee(uint64_t byteCount)
|
||||
{
|
||||
constexpr uint64_t mul = static_cast<uint64_t>(createByteMultiplier);
|
||||
if (byteCount > std::numeric_limits<uint64_t>::max() / mul)
|
||||
return feeCalculationFailed; // overflow
|
||||
uint64_t const uf = byteCount * mul;
|
||||
if (uf > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()))
|
||||
return feeCalculationFailed;
|
||||
return static_cast<int64_t>(uf);
|
||||
}
|
||||
|
||||
NotTEC
|
||||
preflightFunctions(STTx const& tx, beast::Journal j)
|
||||
{
|
||||
// Functions must be present if ContractCode is present.
|
||||
if (!tx.isFieldPresent(sfContractCode))
|
||||
return tesSUCCESS;
|
||||
|
||||
if (!tx.isFieldPresent(sfFunctions))
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: ContractCode present but "
|
||||
"Functions missing.";
|
||||
return temARRAY_EMPTY;
|
||||
}
|
||||
|
||||
auto const& functions = tx.getFieldArray(sfFunctions);
|
||||
|
||||
if (functions.empty())
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Functions array empty.";
|
||||
return temARRAY_EMPTY;
|
||||
}
|
||||
|
||||
// Functions must not exceed n entries.
|
||||
if (functions.size() > contract::maxContractFunctions)
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Functions array too large.";
|
||||
return temARRAY_TOO_LARGE;
|
||||
}
|
||||
|
||||
std::unordered_set<Blob, BlobHash> uniqueFunctions;
|
||||
uniqueFunctions.reserve(functions.size());
|
||||
for (auto const& function : functions)
|
||||
{
|
||||
// Functions must be unique by name.
|
||||
auto const& functionName = function.getFieldVL(sfFunctionName);
|
||||
if (!uniqueFunctions.insert(functionName).second)
|
||||
{
|
||||
JLOG(j.trace()) << "Duplicate function name: " << strHex(functionName);
|
||||
return temREDUNDANT;
|
||||
}
|
||||
|
||||
auto const& parameters = function.getFieldArray(sfParameters);
|
||||
|
||||
// Function Parameters must not exceed n entries each.
|
||||
if (parameters.size() > contract::maxContractParams)
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Function Parameters "
|
||||
"array is too large.";
|
||||
return temARRAY_TOO_LARGE;
|
||||
}
|
||||
|
||||
std::unordered_set<Blob, BlobHash> uniqueParameters;
|
||||
uniqueParameters.reserve(parameters.size());
|
||||
|
||||
for (auto const& param : parameters)
|
||||
{
|
||||
// Function Parameter must have a flag.
|
||||
if (!param.isFieldPresent(sfParameterFlag))
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Function Parameter "
|
||||
"is missing flag.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
// Function Parameter must have a type.
|
||||
if (!param.isFieldPresent(sfParameterType))
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Function Parameter "
|
||||
"is missing type.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
// Function Parameter flags must be valid.
|
||||
auto const flags = param.getFieldU32(sfParameterFlag);
|
||||
if (flags & tfContractParameterMask)
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Invalid parameter "
|
||||
"flag in Function.";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
NotTEC
|
||||
preflightInstanceParameters(STTx const& tx, beast::Journal j)
|
||||
{
|
||||
if (!tx.isFieldPresent(sfInstanceParameters))
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const& instanceParameters = tx.getFieldArray(sfInstanceParameters);
|
||||
|
||||
// InstanceParameters must not be empty.
|
||||
if (instanceParameters.empty())
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: InstanceParameters empty array.";
|
||||
return temARRAY_EMPTY;
|
||||
}
|
||||
|
||||
// InstanceParameters must not exceed n entries.
|
||||
if (instanceParameters.size() > contract::maxContractParams)
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: InstanceParameters array "
|
||||
"is too large.";
|
||||
return temARRAY_TOO_LARGE;
|
||||
}
|
||||
|
||||
std::unordered_set<Blob, BlobHash> uniqueParameters;
|
||||
uniqueParameters.reserve(instanceParameters.size());
|
||||
for (auto const& param : instanceParameters)
|
||||
{
|
||||
// Instance Parameter must have a flag.
|
||||
if (!param.isFieldPresent(sfParameterFlag))
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Instance Parameter is missing flag.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
// Instance Parameter must have a type.
|
||||
if (!param.isFieldPresent(sfParameterType))
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Instance Parameter is missing type.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
// Instance Parameter flags must be valid.
|
||||
auto const flags = param.getFieldU32(sfParameterFlag);
|
||||
if (flags & tfContractParameterMask)
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Invalid parameter "
|
||||
"flag in Instance Parameter.";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
}
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
validateParameterMapping(STArray const& params, STArray const& values, beast::Journal j)
|
||||
{
|
||||
if (params.size() != values.size())
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: InstanceParameterValues size "
|
||||
"does not match InstanceParameters size.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NotTEC
|
||||
preflightInstanceParameterValues(STTx const& tx, beast::Journal j)
|
||||
{
|
||||
if (!tx.isFieldPresent(sfInstanceParameterValues))
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const& instanceParameterValues = tx.getFieldArray(sfInstanceParameterValues);
|
||||
|
||||
// InstanceParameters must not be empty.
|
||||
if (instanceParameterValues.empty())
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: InstanceParameterValues is missing.";
|
||||
return temARRAY_EMPTY;
|
||||
}
|
||||
|
||||
// InstanceParameterValues must not exceed n entries.
|
||||
if (instanceParameterValues.size() > contract::maxContractParams)
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: InstanceParameterValues "
|
||||
"array is too large.";
|
||||
return temARRAY_TOO_LARGE;
|
||||
}
|
||||
|
||||
std::unordered_set<Blob, BlobHash> uniqueParameters;
|
||||
uniqueParameters.reserve(instanceParameterValues.size());
|
||||
for (auto const& param : instanceParameterValues)
|
||||
{
|
||||
// Instance Parameter must have a flag.
|
||||
if (!param.isFieldPresent(sfParameterFlag))
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Instance Parameter is missing flag.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
// Instance Parameter must have a value.
|
||||
if (!param.isFieldPresent(sfParameterValue))
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Instance Parameter is "
|
||||
"missing value.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
// Instance Parameter flags must be valid.
|
||||
auto const flags = param.getFieldU32(sfParameterFlag);
|
||||
if (flags & tfContractParameterMask)
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: Invalid parameter "
|
||||
"flag in Instance Parameter.";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
// Only validate the mapping if InstanceParameters are present
|
||||
bool valid = true;
|
||||
if (tx.isFieldPresent(sfInstanceParameters))
|
||||
valid = validateParameterMapping(
|
||||
tx.getFieldArray(sfInstanceParameters), tx.getFieldArray(sfInstanceParameterValues), j);
|
||||
if (!valid)
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: InstanceParameterValues do not match "
|
||||
"InstanceParameters.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
// Validate flags in InstanceParameterValues
|
||||
if (auto const res = preflightFlagParameters(instanceParameterValues, j); !isTesSuccess(res))
|
||||
{
|
||||
JLOG(j.trace()) << "ContractCreate/Modify: InstanceParameterValues flag "
|
||||
"validation failed: "
|
||||
<< transToken(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
isValidParameterFlag(std::uint32_t flags)
|
||||
{
|
||||
return (flags & tfContractParameterMask) == 0;
|
||||
}
|
||||
|
||||
NotTEC
|
||||
preflightFlagParameters(STArray const& parameters, beast::Journal j)
|
||||
{
|
||||
for (auto const& param : parameters)
|
||||
{
|
||||
if (!param.isFieldPresent(sfParameterFlag) ||
|
||||
!isValidParameterFlag(param.getFieldU32(sfParameterFlag)))
|
||||
continue; // Skip invalid flags
|
||||
|
||||
switch (param.getFieldU32(sfParameterFlag))
|
||||
{
|
||||
case tfSendAmount: {
|
||||
if (!param.isFieldPresent(sfParameterValue))
|
||||
return temMALFORMED;
|
||||
auto const& value = param.getFieldData(sfParameterValue);
|
||||
STAmount const amount = value.getFieldAmount();
|
||||
// Preflight Transfer Amount
|
||||
if (isXRP(amount))
|
||||
{
|
||||
if (amount <= beast::kZero)
|
||||
return temBAD_AMOUNT;
|
||||
}
|
||||
else if (amount.holds<Issue>())
|
||||
{
|
||||
if (amount.native() || amount <= beast::kZero)
|
||||
return temBAD_AMOUNT;
|
||||
|
||||
if (badCurrency() == amount.get<Issue>().currency)
|
||||
return temBAD_CURRENCY;
|
||||
}
|
||||
else if (amount.holds<MPTIssue>())
|
||||
{
|
||||
if (amount.native() || amount.mpt() > MPTAmount{kMaxMpTokenAmount} ||
|
||||
amount <= beast::kZero)
|
||||
return temBAD_AMOUNT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tfSendNFToken: {
|
||||
break;
|
||||
}
|
||||
case tfAuthorizeToken: {
|
||||
return temDISABLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
preclaimFlagParameters(
|
||||
ReadView const& view,
|
||||
AccountID const& sourceAccount,
|
||||
AccountID const& contractAccount,
|
||||
STArray const& parameters,
|
||||
beast::Journal j)
|
||||
{
|
||||
for (auto const& param : parameters)
|
||||
{
|
||||
if (!param.isFieldPresent(sfParameterFlag) ||
|
||||
!isValidParameterFlag(param.getFieldU32(sfParameterFlag)))
|
||||
continue; // Skip invalid flags
|
||||
|
||||
switch (param.getFieldU32(sfParameterFlag))
|
||||
{
|
||||
case tfSendAmount: {
|
||||
if (!param.isFieldPresent(sfParameterValue))
|
||||
return tecINTERNAL;
|
||||
|
||||
auto const& value = param.getFieldData(sfParameterValue);
|
||||
STAmount const amount = value.getFieldAmount();
|
||||
// Preclaim Transfer Amount
|
||||
if (isXRP(amount))
|
||||
{
|
||||
auto const accountSle = view.read(keylet::account(sourceAccount));
|
||||
if (!accountSle)
|
||||
return tecINTERNAL;
|
||||
|
||||
auto const& mSourceBalance = accountSle->getFieldAmount(sfBalance);
|
||||
if (mSourceBalance < amount.xrp())
|
||||
return tecUNFUNDED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto ter = canTransferFT(
|
||||
view,
|
||||
sourceAccount,
|
||||
contractAccount,
|
||||
amount,
|
||||
j,
|
||||
SendIssuerHandling::ihIGNORE,
|
||||
SendEscrowHandling::ehIGNORE,
|
||||
SendAuthHandling::ahBOTH,
|
||||
SendFreezeHandling::fhBOTH,
|
||||
SendTransferHandling::thIGNORE,
|
||||
SendBalanceHandling::bhCHECK))
|
||||
{
|
||||
JLOG(j.trace()) << "preclaimFlagParameters: Cannot "
|
||||
"transfer amount: "
|
||||
<< amount;
|
||||
return ter;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tfSendNFToken: {
|
||||
if (!param.isFieldPresent(sfParameterValue))
|
||||
return tecINTERNAL;
|
||||
auto const& value = param.getFieldData(sfParameterValue);
|
||||
auto const& nftokenID = value.getFieldH256();
|
||||
// Preclaim Transfer NFT Token
|
||||
if (!nft::findToken(view, sourceAccount, nftokenID))
|
||||
{
|
||||
JLOG(j.trace())
|
||||
<< "preclaimFlagParameters: Cannot transfer NFT token: " << nftokenID;
|
||||
return tecNO_ENTRY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tfAuthorizeToken: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
doApplyFlagParameters(
|
||||
ApplyView& view,
|
||||
STTx const& tx,
|
||||
AccountID const& sourceAccount,
|
||||
AccountID const& contractAccount,
|
||||
STArray const& parameters,
|
||||
XRPAmount const& priorBalance,
|
||||
beast::Journal j)
|
||||
{
|
||||
for (auto const& param : parameters)
|
||||
{
|
||||
if (!param.isFieldPresent(sfParameterFlag) ||
|
||||
!isValidParameterFlag(param.getFieldU32(sfParameterFlag)))
|
||||
continue; // Skip invalid flags
|
||||
|
||||
switch (param.getFieldU32(sfParameterFlag))
|
||||
{
|
||||
case tfSendAmount: {
|
||||
if (!param.isFieldPresent(sfParameterValue))
|
||||
return tecINTERNAL;
|
||||
|
||||
auto const& value = param.getFieldData(sfParameterValue);
|
||||
STAmount const amount = value.getFieldAmount();
|
||||
if (auto ter = accountSend(
|
||||
view, sourceAccount, contractAccount, amount, j, {}, WaiveTransferFee::No);
|
||||
!isTesSuccess(ter))
|
||||
{
|
||||
JLOG(j.trace()) << "doApplyFlagParameters: Failed to send amount: " << amount;
|
||||
return ter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tfSendNFToken: {
|
||||
if (!param.isFieldPresent(sfParameterValue))
|
||||
return tecINTERNAL;
|
||||
auto const& value = param.getFieldData(sfParameterValue);
|
||||
auto const& nftokenID = value.getFieldH256();
|
||||
if (auto ter =
|
||||
nft::transferNFToken(view, sourceAccount, contractAccount, nftokenID, j);
|
||||
!isTesSuccess(ter))
|
||||
{
|
||||
JLOG(j.trace())
|
||||
<< "doApplyFlagParameters: Failed to send NFT token: " << nftokenID;
|
||||
return ter;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tfAuthorizeToken: {
|
||||
return tecINTERNAL;
|
||||
// if (!param.isFieldPresent(sfParameterValue))
|
||||
// return tecINTERNAL;
|
||||
// // Handle tfAuthorizeToken if needed
|
||||
// auto const& value = param.getFieldData(sfParameterValue);
|
||||
// STAmount limit = value.getFieldAmount();
|
||||
// Asset asset = Asset{limit.issue()};
|
||||
// if (auto ter = canAddHolding(view, asset);
|
||||
// !isTesSuccess(ter))
|
||||
// {
|
||||
// JLOG(j.trace()) << "doApplyFlagParameters: Cannot add "
|
||||
// "holding for asset: "
|
||||
// << to_string(asset);
|
||||
// return ter;
|
||||
// }
|
||||
// // Set the issuer to the contract account for the holding
|
||||
// limit.setIssuer(contractAccount);
|
||||
// if (auto ter = addEmptyHolding(
|
||||
// view, contractAccount, priorBalance, asset, limit,
|
||||
// j);
|
||||
// !isTesSuccess(ter))
|
||||
// {
|
||||
// JLOG(j.trace()) << "doApplyFlagParameters: Failed to add
|
||||
// "
|
||||
// "holding for asset: "
|
||||
// << to_string(asset);
|
||||
// return ter;
|
||||
// }
|
||||
// break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
contractDataReserve(uint32_t size)
|
||||
{
|
||||
// Divide by dataByteMultiplier and round up to the nearest whole number
|
||||
return (size + dataByteMultiplier - 1U) / dataByteMultiplier;
|
||||
}
|
||||
|
||||
TER
|
||||
setContractData(
|
||||
ServiceRegistry& registry,
|
||||
ApplyView& view,
|
||||
AccountID const& account,
|
||||
AccountID const& contractAccount,
|
||||
STJson const& data)
|
||||
{
|
||||
auto const j = registry.getJournal("View");
|
||||
auto const sleAccount = view.peek(keylet::account(account));
|
||||
if (!sleAccount)
|
||||
return tefINTERNAL;
|
||||
|
||||
// if the blob is too large don't set it
|
||||
if (data.size() > maxContractDataSize)
|
||||
return temARRAY_TOO_LARGE;
|
||||
|
||||
auto dataKeylet = keylet::contractData(account, contractAccount);
|
||||
auto dataSle = view.peek(dataKeylet);
|
||||
|
||||
// DELETE
|
||||
if (data.size() == 0)
|
||||
{
|
||||
if (!dataSle)
|
||||
return tesSUCCESS;
|
||||
|
||||
uint32_t const oldDataReserve =
|
||||
contractDataReserve(dataSle->getFieldJson(sfContractJson).size());
|
||||
|
||||
std::uint64_t const page = (*dataSle)[sfOwnerNode];
|
||||
// Remove the page from the account directory
|
||||
if (!view.dirRemove(keylet::ownerDir(account), page, dataKeylet.key, false))
|
||||
return tefBAD_LEDGER;
|
||||
|
||||
// remove the actual contract data sle
|
||||
view.erase(dataSle);
|
||||
|
||||
// reduce the owner count
|
||||
decreaseOwnerCount(view, sleAccount, {}, oldDataReserve, j);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
std::uint32_t const ownerCount{(*sleAccount)[sfOwnerCount]};
|
||||
bool const createNew = !dataSle;
|
||||
if (createNew)
|
||||
{
|
||||
// CREATE
|
||||
uint32_t const dataReserve = contractDataReserve(data.size());
|
||||
uint32_t const newReserve = ownerCount + dataReserve;
|
||||
XRPAmount const newReserveAmount{view.fees().accountReserve(newReserve, 1)};
|
||||
if (STAmount((*sleAccount)[sfBalance]).xrp() < newReserveAmount)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
increaseOwnerCount(view, sleAccount, {}, dataReserve, j);
|
||||
// create an entry
|
||||
dataSle = std::make_shared<SLE>(dataKeylet);
|
||||
dataSle->setFieldJson(sfContractJson, data);
|
||||
dataSle->setAccountID(sfOwner, account);
|
||||
dataSle->setAccountID(sfContractAccount, contractAccount);
|
||||
|
||||
auto const page =
|
||||
view.dirInsert(keylet::ownerDir(account), dataKeylet.key, describeOwnerDir(account));
|
||||
if (!page)
|
||||
return tecDIR_FULL;
|
||||
|
||||
dataSle->setFieldU64(sfOwnerNode, *page);
|
||||
|
||||
// add new data to ledger
|
||||
view.insert(dataSle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// UPDATE
|
||||
uint32_t const oldDataReserve =
|
||||
contractDataReserve(dataSle->getFieldJson(sfContractJson).size());
|
||||
uint32_t const newDataReserve = contractDataReserve(data.size());
|
||||
if (newDataReserve != oldDataReserve)
|
||||
{
|
||||
// if the reserve changes, we need to adjust the owner count
|
||||
uint32_t const newReserve = ownerCount - oldDataReserve + newDataReserve;
|
||||
XRPAmount const newReserveAmount{view.fees().accountReserve(newReserve, 1)};
|
||||
if (STAmount((*sleAccount)[sfBalance]).xrp() < newReserveAmount)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
increaseOwnerCount(view, sleAccount, {}, newReserve, j);
|
||||
}
|
||||
|
||||
// update the data
|
||||
dataSle->setFieldJson(sfContractJson, data);
|
||||
view.update(dataSle);
|
||||
}
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
finalizeContractData(
|
||||
ServiceRegistry& registry,
|
||||
ApplyView& view,
|
||||
AccountID const& contractAccount,
|
||||
ContractDataMap const& dataMap,
|
||||
ContractEventMap const& eventMap,
|
||||
uint256 const& txnID)
|
||||
{
|
||||
auto const& j = registry.getJournal("View");
|
||||
uint16_t changeCount = 0;
|
||||
|
||||
for (auto const& [name, data] : eventMap)
|
||||
registry.getOPs().pubContractEvent(name, data);
|
||||
|
||||
for (auto const& accEntry : dataMap)
|
||||
{
|
||||
auto const& acc = accEntry.first;
|
||||
auto const& cacheEntry = accEntry.second;
|
||||
bool const is_modified = cacheEntry.first;
|
||||
auto const& jsonData = cacheEntry.second;
|
||||
if (is_modified)
|
||||
{
|
||||
changeCount++;
|
||||
if (changeCount > maxDataModifications)
|
||||
{
|
||||
// overflow
|
||||
JLOG(j.trace()) << "ContractError[TX:" << txnID
|
||||
<< "]: SetContractData failed: Too many data changes";
|
||||
return tecBYTECODE_REJECTED;
|
||||
}
|
||||
|
||||
TER result = setContractData(registry, view, acc, contractAccount, jsonData);
|
||||
if (!isTesSuccess(result))
|
||||
{
|
||||
JLOG(j.warn()) << "ContractError[TX:" << txnID
|
||||
<< "]: SetContractData failed: " << result << " Account: " << acc;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
} // namespace contract
|
||||
} // namespace xrpl
|
||||
@@ -2,11 +2,14 @@
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/algorithm.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/Dir.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/View.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
@@ -1082,4 +1085,49 @@ checkTrustlineDeepFrozen(
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
transferNFToken(
|
||||
ApplyView& view,
|
||||
AccountID const& buyer,
|
||||
AccountID const& seller,
|
||||
uint256 const& nftokenID,
|
||||
beast::Journal j)
|
||||
{
|
||||
auto tokenAndPage = nft::findTokenAndPage(view, seller, nftokenID);
|
||||
|
||||
if (!tokenAndPage)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (auto const ret = nft::removeToken(view, seller, nftokenID, tokenAndPage->page);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
auto const sleBuyer = view.read(keylet::account(buyer));
|
||||
if (!sleBuyer)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
std::uint32_t const buyerOwnerCountBefore = sleBuyer->getFieldU32(sfOwnerCount);
|
||||
|
||||
auto const insertRet = nft::insertToken(view, buyer, std::move(tokenAndPage->token));
|
||||
|
||||
// There was an issue where the buyer accepts a sell offer, the ledger
|
||||
// didn't check if the buyer has enough reserve, meaning that buyer can get
|
||||
// NFTs free of reserve.
|
||||
// To check if there is sufficient reserve, we cannot use preFeeBalance_
|
||||
// because NFT is sold for a price. So we must use the balance after
|
||||
// the deduction of the potential offer price. A small caveat here is
|
||||
// that the balance has already deducted the transaction fee, meaning
|
||||
// that the reserve requirement is a few drops higher.
|
||||
auto const buyerBalance = sleBuyer->getFieldAmount(sfBalance);
|
||||
|
||||
auto const buyerOwnerCountAfter = sleBuyer->getFieldU32(sfOwnerCount);
|
||||
if (buyerOwnerCountAfter > buyerOwnerCountBefore)
|
||||
{
|
||||
if (buyerBalance < accountReserve(view, sleBuyer, j))
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
|
||||
return insertRet;
|
||||
}
|
||||
|
||||
} // namespace xrpl::nft
|
||||
|
||||
167
src/libxrpl/protocol/Emitable.cpp
Normal file
167
src/libxrpl/protocol/Emitable.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/protocol/Emitable.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Permissions.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
Emitable::Emitable()
|
||||
{
|
||||
emitableTx_ = {
|
||||
#pragma push_macro("TRANSACTION")
|
||||
#undef TRANSACTION
|
||||
|
||||
#define TRANSACTION(tag, value, name, delegatable, amendment, permissions, emitable, fields) \
|
||||
{value, emitable},
|
||||
#include <xrpl/protocol/detail/transactions.macro>
|
||||
|
||||
#undef TRANSACTION
|
||||
#pragma pop_macro("TRANSACTION")
|
||||
};
|
||||
|
||||
granularEmitableMap_ = {
|
||||
#pragma push_macro("EMITABLE")
|
||||
#undef EMITABLE
|
||||
|
||||
#define EMITABLE(type, txType, value) {#type, type},
|
||||
|
||||
#include <xrpl/protocol/detail/emitable.macro>
|
||||
|
||||
#undef EMITABLE
|
||||
#pragma pop_macro("EMITABLE")
|
||||
};
|
||||
|
||||
granularNameMap_ = {
|
||||
#pragma push_macro("EMITABLE")
|
||||
#undef EMITABLE
|
||||
|
||||
#define EMITABLE(type, txType, value) {type, #type},
|
||||
|
||||
#include <xrpl/protocol/detail/emitable.macro>
|
||||
|
||||
#undef EMITABLE
|
||||
#pragma pop_macro("EMITABLE")
|
||||
};
|
||||
|
||||
granularTxTypeMap_ = {
|
||||
#pragma push_macro("EMITABLE")
|
||||
#undef EMITABLE
|
||||
|
||||
#define EMITABLE(type, txType, value) {type, txType},
|
||||
|
||||
#include <xrpl/protocol/detail/emitable.macro>
|
||||
|
||||
#undef EMITABLE
|
||||
#pragma pop_macro("EMITABLE")
|
||||
};
|
||||
|
||||
for ([[maybe_unused]] auto const& emitable : granularEmitableMap_)
|
||||
XRPL_ASSERT(
|
||||
emitable.second > UINT16_MAX,
|
||||
"xrpl::Emitable::granularEmitableMap_ : granular emitable "
|
||||
"value must not exceed the maximum uint16_t value.");
|
||||
}
|
||||
|
||||
Emitable const&
|
||||
Emitable::getInstance()
|
||||
{
|
||||
static Emitable const instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
Emitable::getEmitableName(std::uint32_t const value) const
|
||||
{
|
||||
auto const emitableValue = static_cast<GranularEmitableType>(value);
|
||||
if (auto const granular = getGranularName(emitableValue))
|
||||
return granular;
|
||||
|
||||
// not a granular emitable, check if it maps to a transaction type
|
||||
auto const txType = emitableToTxType(value);
|
||||
if (auto const* item = TxFormats::getInstance().findByType(txType); item != nullptr)
|
||||
return item->getName();
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::uint32_t>
|
||||
Emitable::getGranularValue(std::string const& name) const
|
||||
{
|
||||
auto const it = granularEmitableMap_.find(name);
|
||||
if (it != granularEmitableMap_.end())
|
||||
return static_cast<uint32_t>(it->second);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
Emitable::getGranularName(GranularEmitableType const& value) const
|
||||
{
|
||||
auto const it = granularNameMap_.find(value);
|
||||
if (it != granularNameMap_.end())
|
||||
return it->second;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<TxType>
|
||||
Emitable::getGranularTxType(GranularEmitableType const& gpType) const
|
||||
{
|
||||
auto const it = granularTxTypeMap_.find(gpType);
|
||||
if (it != granularTxTypeMap_.end())
|
||||
return it->second;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool
|
||||
Emitable::isEmitable(std::uint32_t const& emitableValue) const
|
||||
{
|
||||
auto const granularEmitable = getGranularName(static_cast<GranularEmitableType>(emitableValue));
|
||||
if (granularEmitable)
|
||||
// granular emitables are always allowed to be delegated
|
||||
return true;
|
||||
|
||||
auto const txType = emitableToTxType(emitableValue);
|
||||
auto const it = emitableTx_.find(txType);
|
||||
|
||||
// if (rules.enabled(fixDelegateV1_1))
|
||||
// {
|
||||
// if (it == delegatableTx_.end())
|
||||
// return false;
|
||||
|
||||
// auto const txFeaturesIt = txFeatureMap_.find(txType);
|
||||
// XRPL_ASSERT(
|
||||
// txFeaturesIt != txFeatureMap_.end(),
|
||||
// "xrpl::Emitables::isDelegatable : tx exists in txFeatureMap_");
|
||||
|
||||
// // fixDelegateV1_1: Delegation is only allowed if the required
|
||||
// amendment
|
||||
// // for the transaction is enabled. For transactions that do not
|
||||
// require
|
||||
// // an amendment, delegation is always allowed.
|
||||
// if (txFeaturesIt->second != uint256{} &&
|
||||
// !rules.enabled(txFeaturesIt->second))
|
||||
// return false;
|
||||
// }
|
||||
|
||||
if (it != emitableTx_.end() && it->second == Emittance::notEmitable)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Emitable::txToEmitableType(TxType const& type) const
|
||||
{
|
||||
return static_cast<uint32_t>(type) + 1;
|
||||
}
|
||||
|
||||
TxType
|
||||
Emitable::emitableToTxType(uint32_t const& value) const
|
||||
{
|
||||
return static_cast<TxType>(value - 1);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -105,8 +105,11 @@ enum class LedgerNameSpace : std::uint16_t {
|
||||
Loan = 'L',
|
||||
Sponsorship = '>',
|
||||
|
||||
ContractSource = 'Z',
|
||||
Contract = 'c',
|
||||
ContractData = 'b',
|
||||
|
||||
// No longer used or supported. Left here to reserve the space to avoid accidental reuse.
|
||||
Contract [[deprecated]] = 'c',
|
||||
Generator [[deprecated]] = 'g',
|
||||
Nickname [[deprecated]] = 'n',
|
||||
};
|
||||
@@ -589,6 +592,24 @@ permissionedDomain(uint256 const& domainID) noexcept
|
||||
return {ltPERMISSIONED_DOMAIN, domainID};
|
||||
}
|
||||
|
||||
Keylet
|
||||
contractSource(uint256 const& contractHash) noexcept
|
||||
{
|
||||
return {ltCONTRACT_SOURCE, indexHash(LedgerNameSpace::ContractSource, contractHash)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
contract(uint256 const& contractHash, AccountID const& owner, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {ltCONTRACT, indexHash(LedgerNameSpace::Contract, contractHash, owner, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
contractData(AccountID const& owner, AccountID const& contractAccount) noexcept
|
||||
{
|
||||
return {ltCONTRACT_DATA, indexHash(LedgerNameSpace::ContractData, owner, contractAccount)};
|
||||
}
|
||||
|
||||
} // namespace keylet
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -137,9 +137,9 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfCredentialType, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfPermission.jsonName.cStr(), sfPermission.getCode(), {{sfPermissionValue, SoeRequired}});
|
||||
add(sfPermission.jsonName, sfPermission.getCode(), {{sfPermissionValue, SoeRequired}});
|
||||
|
||||
add(sfBatchSigner.jsonName.cStr(),
|
||||
add(sfBatchSigner.jsonName,
|
||||
sfBatchSigner.getCode(),
|
||||
{{sfAccount, SoeRequired},
|
||||
{sfSigningPubKey, SoeOptional},
|
||||
@@ -161,13 +161,42 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfSigners, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfSponsorSignature.jsonName.cStr(),
|
||||
add(sfSponsorSignature.jsonName,
|
||||
sfSponsorSignature.getCode(),
|
||||
{
|
||||
{sfSigningPubKey, SoeOptional},
|
||||
{sfTxnSignature, SoeOptional},
|
||||
{sfSigners, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfFunction.jsonName,
|
||||
sfFunction.getCode(),
|
||||
{
|
||||
{sfFunctionName, SoeRequired},
|
||||
{sfParameters, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfInstanceParameter.jsonName,
|
||||
sfInstanceParameter.getCode(),
|
||||
{
|
||||
{sfParameterFlag, SoeRequired},
|
||||
{sfParameterType, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfInstanceParameterValue.jsonName,
|
||||
sfInstanceParameterValue.getCode(),
|
||||
{
|
||||
{sfParameterFlag, SoeRequired},
|
||||
{sfParameterValue, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfParameter.jsonName,
|
||||
sfParameter.getCode(),
|
||||
{
|
||||
{sfParameterFlag, SoeOptional},
|
||||
{sfParameterType, SoeOptional},
|
||||
{sfParameterValue, SoeOptional},
|
||||
});
|
||||
}
|
||||
|
||||
InnerObjectFormats const&
|
||||
|
||||
973
src/libxrpl/protocol/STData.cpp
Normal file
973
src/libxrpl/protocol/STData.cpp
Normal file
@@ -0,0 +1,973 @@
|
||||
#include <xrpl/protocol/STData.h>
|
||||
|
||||
#include <xrpl/basics/Buffer.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/StringUtilities.h>
|
||||
#include <xrpl/beast/core/LexicalCast.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STBlob.h>
|
||||
#include <xrpl/protocol/STCurrency.h>
|
||||
#include <xrpl/protocol/STIssue.h>
|
||||
#include <xrpl/protocol/STNumber.h>
|
||||
#include <xrpl/protocol/detail/STVar.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <typename U, typename S>
|
||||
constexpr std::enable_if_t<std::is_unsigned<U>::value && std::is_signed<S>::value, U>
|
||||
to_unsigned(S value)
|
||||
{
|
||||
if (value < 0 || std::numeric_limits<U>::max() < value)
|
||||
Throw<std::runtime_error>("Value out of range");
|
||||
return static_cast<U>(value);
|
||||
}
|
||||
|
||||
template <typename U1, typename U2>
|
||||
constexpr std::enable_if_t<std::is_unsigned<U1>::value && std::is_unsigned<U2>::value, U1>
|
||||
to_unsigned(U2 value)
|
||||
{
|
||||
if (std::numeric_limits<U1>::max() < value)
|
||||
Throw<std::runtime_error>("Value out of range");
|
||||
return static_cast<U1>(value);
|
||||
}
|
||||
|
||||
// TODO
|
||||
STData::STData(SField const& n) : STBase(n), inner_type_(STI_NOTPRESENT), data_(STBase{})
|
||||
{
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, unsigned char v)
|
||||
: STBase(n)
|
||||
, inner_type_(STI_UINT8)
|
||||
, data_(detail::STVar(detail::gDefaultObject, sfCloseResolution))
|
||||
{
|
||||
setFieldUsingSetValue<STUInt8>(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, std::uint16_t v)
|
||||
: STBase(n)
|
||||
, inner_type_(STI_UINT16)
|
||||
, data_(detail::STVar(detail::gDefaultObject, sfSignerWeight))
|
||||
{
|
||||
setFieldUsingSetValue<STUInt16>(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, std::uint32_t v)
|
||||
: STBase(n), inner_type_(STI_UINT32), data_(detail::STVar(detail::gDefaultObject, sfNetworkID))
|
||||
{
|
||||
setFieldUsingSetValue<STUInt32>(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, std::uint64_t v)
|
||||
: STBase(n), inner_type_(STI_UINT64), data_(detail::STVar(detail::gDefaultObject, sfIndexNext))
|
||||
{
|
||||
setFieldUsingSetValue<STUInt64>(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, uint128 const& v)
|
||||
: STBase(n), inner_type_(STI_UINT128), data_(detail::STVar(detail::gDefaultObject, sfEmailHash))
|
||||
{
|
||||
setFieldUsingSetValue<STUInt128>(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, uint160 const& v)
|
||||
: STBase(n)
|
||||
, inner_type_(STI_UINT160)
|
||||
, data_(detail::STVar(detail::gDefaultObject, sfTakerPaysCurrency))
|
||||
{
|
||||
setFieldUsingSetValue<STUInt160>(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, uint192 const& v)
|
||||
: STBase(n)
|
||||
, inner_type_(STI_UINT192)
|
||||
, data_(detail::STVar(detail::gDefaultObject, sfMPTokenIssuanceID))
|
||||
{
|
||||
setFieldUsingSetValue<STUInt192>(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, uint256 const& v)
|
||||
: STBase(n)
|
||||
, inner_type_(STI_UINT256)
|
||||
, data_(detail::STVar(detail::gDefaultObject, sfLedgerHash))
|
||||
{
|
||||
setFieldUsingSetValue<STUInt256>(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, Blob const& v)
|
||||
: STBase(n), inner_type_(STI_VL), data_(detail::STVar(detail::gDefaultObject, sfURI))
|
||||
{
|
||||
setFieldUsingSetValue<STBlob>(Buffer(v.data(), v.size()));
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, Slice const& v)
|
||||
: STBase(n), inner_type_(STI_VL), data_(detail::STVar(detail::gDefaultObject, sfURI))
|
||||
{
|
||||
setFieldUsingSetValue<STBlob>(Buffer(v.data(), v.size()));
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, STAmount const& v)
|
||||
: STBase(n), inner_type_(STI_AMOUNT), data_(detail::STVar(detail::gDefaultObject, sfAmount))
|
||||
{
|
||||
setFieldUsingAssignment(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, AccountID const& v)
|
||||
: STBase(n), inner_type_(STI_ACCOUNT), data_(detail::STVar(detail::gDefaultObject, sfAccount))
|
||||
{
|
||||
setFieldUsingSetValue<STAccount>(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, STIssue const& v)
|
||||
: STBase(n), inner_type_(STI_ISSUE), data_(detail::STVar(detail::gDefaultObject, sfAsset))
|
||||
{
|
||||
setFieldUsingAssignment(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, STCurrency const& v)
|
||||
: STBase(n)
|
||||
, inner_type_(STI_CURRENCY)
|
||||
, data_(detail::STVar(detail::gDefaultObject, sfBaseAsset))
|
||||
{
|
||||
setFieldUsingAssignment(v);
|
||||
}
|
||||
|
||||
STData::STData(SField const& n, STNumber const& v)
|
||||
: STBase(n), inner_type_(STI_NUMBER), data_(detail::STVar(detail::gDefaultObject, sfNumber))
|
||||
{
|
||||
setFieldUsingAssignment(v);
|
||||
}
|
||||
|
||||
STData::STData(SerialIter& sit, SField const& name) : STBase(name), data_(STBase{})
|
||||
{
|
||||
std::uint16_t const stype = SerializedTypeID(sit.get16());
|
||||
inner_type_ = stype;
|
||||
SerializedTypeID const s = static_cast<SerializedTypeID>(stype);
|
||||
switch (s)
|
||||
{
|
||||
case STI_UINT8: {
|
||||
data_ = detail::STVar(sit, sfCloseResolution);
|
||||
break;
|
||||
}
|
||||
case STI_UINT16: {
|
||||
data_ = detail::STVar(sit, sfSignerWeight);
|
||||
break;
|
||||
}
|
||||
case STI_UINT32: {
|
||||
data_ = detail::STVar(sit, sfNetworkID);
|
||||
break;
|
||||
}
|
||||
case STI_UINT64: {
|
||||
data_ = detail::STVar(sit, sfIndexNext);
|
||||
break;
|
||||
}
|
||||
case STI_UINT128: {
|
||||
data_ = detail::STVar(sit, sfEmailHash);
|
||||
break;
|
||||
}
|
||||
case STI_UINT160: {
|
||||
data_ = detail::STVar(sit, sfTakerPaysCurrency);
|
||||
break;
|
||||
}
|
||||
case STI_UINT192: {
|
||||
data_ = detail::STVar(sit, sfMPTokenIssuanceID);
|
||||
break;
|
||||
}
|
||||
case STI_UINT256: {
|
||||
data_ = detail::STVar(sit, sfLedgerHash);
|
||||
break;
|
||||
}
|
||||
case STI_VL: {
|
||||
data_ = detail::STVar(sit, sfURI);
|
||||
break;
|
||||
}
|
||||
case STI_AMOUNT: {
|
||||
data_ = detail::STVar(sit, sfAmount);
|
||||
break;
|
||||
}
|
||||
case STI_ACCOUNT: {
|
||||
data_ = detail::STVar(sit, sfAccount);
|
||||
break;
|
||||
}
|
||||
case STI_ISSUE: {
|
||||
data_ = detail::STVar(sit, sfAsset);
|
||||
break;
|
||||
}
|
||||
case STI_CURRENCY: {
|
||||
data_ = detail::STVar(sit, sfBaseAsset);
|
||||
break;
|
||||
}
|
||||
case STI_NUMBER: {
|
||||
data_ = detail::STVar(sit, sfNumber);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Throw<std::runtime_error>("STData: unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
STBase*
|
||||
STData::copy(std::size_t n, void* buf) const
|
||||
{
|
||||
return emplace(n, buf, *this);
|
||||
}
|
||||
|
||||
STBase*
|
||||
STData::move(std::size_t n, void* buf)
|
||||
{
|
||||
return emplace(n, buf, std::move(*this));
|
||||
}
|
||||
|
||||
std::size_t
|
||||
STData::size() const
|
||||
{
|
||||
switch (static_cast<SerializedTypeID>(inner_type_))
|
||||
{
|
||||
case STI_UINT8: {
|
||||
return sizeof(uint8_t);
|
||||
}
|
||||
case STI_UINT16: {
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
case STI_UINT32: {
|
||||
return sizeof(uint32_t);
|
||||
}
|
||||
case STI_UINT64: {
|
||||
return sizeof(uint64_t);
|
||||
}
|
||||
case STI_UINT128: {
|
||||
return uint128::size();
|
||||
}
|
||||
case STI_UINT160: {
|
||||
return uint160::size();
|
||||
}
|
||||
case STI_UINT192: {
|
||||
return uint192::size();
|
||||
}
|
||||
case STI_UINT256: {
|
||||
return uint256::size();
|
||||
}
|
||||
case STI_VL: {
|
||||
STBlob const& st_blob = data_.get().downcast<STBlob>();
|
||||
return st_blob.size();
|
||||
}
|
||||
case STI_AMOUNT: {
|
||||
// TODO: STAmount::size()
|
||||
STAmount const& st_amt = data_.get().downcast<STAmount>();
|
||||
return st_amt.native() ? 8 : 48;
|
||||
}
|
||||
case STI_ACCOUNT: {
|
||||
return uint160::size();
|
||||
}
|
||||
case STI_ISSUE: {
|
||||
// const STIssue& st_issue = data_.get().downcast<STIssue>();
|
||||
return 40; // 20 bytes for currency + 20 bytes for account
|
||||
}
|
||||
case STI_CURRENCY: {
|
||||
// const STCurrency& st_currency =
|
||||
// data_.get().downcast<STCurrency>();
|
||||
return 20; // 20 bytes for currency
|
||||
}
|
||||
case STI_NUMBER: {
|
||||
return sizeof(double);
|
||||
}
|
||||
default:
|
||||
Throw<std::runtime_error>("STData: unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
SerializedTypeID
|
||||
STData::getSType() const
|
||||
{
|
||||
return STI_DATA;
|
||||
}
|
||||
|
||||
void
|
||||
STData::add(Serializer& s) const
|
||||
{
|
||||
s.add16(inner_type_);
|
||||
|
||||
switch (static_cast<SerializedTypeID>(inner_type_))
|
||||
{
|
||||
case STI_UINT8: {
|
||||
STUInt8 const& st_uint8 = data_.get().downcast<STUInt8>();
|
||||
st_uint8.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_UINT16: {
|
||||
STUInt16 const& st_uint16 = data_.get().downcast<STUInt16>();
|
||||
st_uint16.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_UINT32: {
|
||||
STUInt32 const& st_uint32 = data_.get().downcast<STUInt32>();
|
||||
st_uint32.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_UINT64: {
|
||||
STUInt64 const& st_uint64 = data_.get().downcast<STUInt64>();
|
||||
st_uint64.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_UINT128: {
|
||||
STUInt128 const& st_uint128 = data_.get().downcast<STUInt128>();
|
||||
st_uint128.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_UINT160: {
|
||||
STUInt160 const& st_uint160 = data_.get().downcast<STUInt160>();
|
||||
st_uint160.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_UINT192: {
|
||||
STUInt192 const& st_uint192 = data_.get().downcast<STUInt192>();
|
||||
st_uint192.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_UINT256: {
|
||||
STUInt256 const& st_uint256 = data_.get().downcast<STUInt256>();
|
||||
st_uint256.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_VL: {
|
||||
STBlob const& st_blob = data_.get().downcast<STBlob>();
|
||||
st_blob.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_AMOUNT: {
|
||||
STAmount const& st_amt = data_.get().downcast<STAmount>();
|
||||
st_amt.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_ACCOUNT: {
|
||||
STAccount const& st_acc = data_.get().downcast<STAccount>();
|
||||
st_acc.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_ISSUE: {
|
||||
STIssue const& st_issue = data_.get().downcast<STIssue>();
|
||||
st_issue.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_CURRENCY: {
|
||||
STCurrency const& st_currency = data_.get().downcast<STCurrency>();
|
||||
st_currency.add(s);
|
||||
break;
|
||||
}
|
||||
case STI_NUMBER: {
|
||||
STNumber const& st_number = data_.get().downcast<STNumber>();
|
||||
st_number.add(s);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Throw<std::runtime_error>("STData: unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
STData::isEquivalent(STBase const& t) const
|
||||
{
|
||||
auto const* const tPtr = dynamic_cast<STData const*>(&t);
|
||||
return tPtr && (default_ == tPtr->default_) && (inner_type_ == tPtr->inner_type_) &&
|
||||
(data_ == tPtr->data_);
|
||||
}
|
||||
|
||||
bool
|
||||
STData::isDefault() const
|
||||
{
|
||||
return default_;
|
||||
}
|
||||
|
||||
std::string
|
||||
STData::getInnerTypeString() const
|
||||
{
|
||||
std::string inner_type_str = "Unknown";
|
||||
switch (static_cast<SerializedTypeID>(inner_type_))
|
||||
{
|
||||
case STI_UINT8:
|
||||
inner_type_str = "UINT8";
|
||||
break;
|
||||
case STI_UINT16:
|
||||
inner_type_str = "UINT16";
|
||||
break;
|
||||
case STI_UINT32:
|
||||
inner_type_str = "UINT32";
|
||||
break;
|
||||
case STI_UINT64:
|
||||
inner_type_str = "UINT64";
|
||||
break;
|
||||
case STI_UINT128:
|
||||
inner_type_str = "UINT128";
|
||||
break;
|
||||
case STI_UINT160:
|
||||
inner_type_str = "UINT160";
|
||||
break;
|
||||
case STI_UINT192:
|
||||
inner_type_str = "UINT192";
|
||||
break;
|
||||
case STI_UINT256:
|
||||
inner_type_str = "UINT256";
|
||||
break;
|
||||
case STI_VL:
|
||||
inner_type_str = "VL";
|
||||
break;
|
||||
case STI_AMOUNT:
|
||||
inner_type_str = "AMOUNT";
|
||||
break;
|
||||
case STI_ACCOUNT:
|
||||
inner_type_str = "ACCOUNT";
|
||||
break;
|
||||
case STI_ISSUE:
|
||||
inner_type_str = "ISSUE";
|
||||
break;
|
||||
case STI_CURRENCY:
|
||||
inner_type_str = "CURRENCY";
|
||||
break;
|
||||
case STI_NUMBER:
|
||||
inner_type_str = "NUMBER";
|
||||
break;
|
||||
// Add other known types as needed
|
||||
default:
|
||||
inner_type_str = std::to_string(inner_type_);
|
||||
}
|
||||
|
||||
return inner_type_str;
|
||||
}
|
||||
|
||||
std::string
|
||||
STData::getText() const
|
||||
{
|
||||
std::string const inner_type_str = getInnerTypeString();
|
||||
return "STData{InnerType: " + inner_type_str + ", Data: " + data_.get().getText() + "}";
|
||||
}
|
||||
|
||||
json::Value
|
||||
STData::getJson(JsonOptions options) const
|
||||
{
|
||||
json::Value ret(json::ValueType::Object);
|
||||
ret[jss::type] = getInnerTypeString();
|
||||
ret[jss::value] = data_.get().getJson(options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
STBase*
|
||||
STData::makeFieldPresent()
|
||||
{
|
||||
STBase* f = &data_.get(); // getPIndex(index);
|
||||
|
||||
if (f->getSType() != STI_NOTPRESENT)
|
||||
return f;
|
||||
|
||||
data_ = detail::STVar(detail::gNonPresentObject, f->getFName());
|
||||
return &data_.get();
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldU8(unsigned char v)
|
||||
{
|
||||
inner_type_ = STI_UINT8;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfCloseResolution);
|
||||
setFieldUsingSetValue<STUInt8>(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldU16(std::uint16_t v)
|
||||
{
|
||||
inner_type_ = STI_UINT16;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfSignerWeight);
|
||||
setFieldUsingSetValue<STUInt16>(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldU32(std::uint32_t v)
|
||||
{
|
||||
inner_type_ = STI_UINT32;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfNetworkID);
|
||||
setFieldUsingSetValue<STUInt32>(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldU64(std::uint64_t v)
|
||||
{
|
||||
inner_type_ = STI_UINT64;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfIndexNext);
|
||||
setFieldUsingSetValue<STUInt64>(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldH128(uint128 const& v)
|
||||
{
|
||||
inner_type_ = STI_UINT128;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfEmailHash);
|
||||
setFieldUsingSetValue<STUInt128>(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldH160(uint160 const& v)
|
||||
{
|
||||
inner_type_ = STI_UINT160;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfTakerPaysCurrency);
|
||||
setFieldUsingSetValue<STUInt160>(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldH192(uint192 const& v)
|
||||
{
|
||||
inner_type_ = STI_UINT192;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfMPTokenIssuanceID);
|
||||
setFieldUsingSetValue<STUInt192>(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldH256(uint256 const& v)
|
||||
{
|
||||
inner_type_ = STI_UINT256;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfLedgerHash);
|
||||
setFieldUsingSetValue<STUInt256>(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldVL(Blob const& v)
|
||||
{
|
||||
inner_type_ = STI_VL;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfData);
|
||||
setFieldUsingSetValue<STBlob>(Buffer(v.data(), v.size()));
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldVL(Slice const& s)
|
||||
{
|
||||
inner_type_ = STI_VL;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfData);
|
||||
setFieldUsingSetValue<STBlob>(Buffer(s.data(), s.size()));
|
||||
}
|
||||
|
||||
void
|
||||
STData::setAccountID(AccountID const& v)
|
||||
{
|
||||
inner_type_ = STI_ACCOUNT;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfAccount);
|
||||
setFieldUsingSetValue<STAccount>(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldAmount(STAmount const& v)
|
||||
{
|
||||
inner_type_ = STI_AMOUNT;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfAmount);
|
||||
setFieldUsingAssignment(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setIssue(STIssue const& v)
|
||||
{
|
||||
inner_type_ = STI_ISSUE;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfAsset);
|
||||
setFieldUsingAssignment(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setCurrency(STCurrency const& v)
|
||||
{
|
||||
inner_type_ = STI_CURRENCY;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfBaseAsset);
|
||||
setFieldUsingAssignment(v);
|
||||
}
|
||||
|
||||
void
|
||||
STData::setFieldNumber(STNumber const& v)
|
||||
{
|
||||
inner_type_ = STI_NUMBER;
|
||||
data_ = detail::STVar(detail::gDefaultObject, sfNumber);
|
||||
setFieldUsingAssignment(v);
|
||||
}
|
||||
|
||||
unsigned char
|
||||
STData::getFieldU8() const
|
||||
{
|
||||
return getFieldByValue<STUInt8>();
|
||||
}
|
||||
|
||||
std::uint16_t
|
||||
STData::getFieldU16() const
|
||||
{
|
||||
return getFieldByValue<STUInt16>();
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
STData::getFieldU32() const
|
||||
{
|
||||
return getFieldByValue<STUInt32>();
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
STData::getFieldU64() const
|
||||
{
|
||||
return getFieldByValue<STUInt64>();
|
||||
}
|
||||
|
||||
uint128
|
||||
STData::getFieldH128() const
|
||||
{
|
||||
return getFieldByValue<STUInt128>();
|
||||
}
|
||||
|
||||
uint160
|
||||
STData::getFieldH160() const
|
||||
{
|
||||
return getFieldByValue<STUInt160>();
|
||||
}
|
||||
|
||||
uint192
|
||||
STData::getFieldH192() const
|
||||
{
|
||||
return getFieldByValue<STUInt192>();
|
||||
}
|
||||
|
||||
uint256
|
||||
STData::getFieldH256() const
|
||||
{
|
||||
return getFieldByValue<STUInt256>();
|
||||
}
|
||||
|
||||
Blob
|
||||
STData::getFieldVL() const
|
||||
{
|
||||
STBlob const empty;
|
||||
STBlob const& b = getFieldByConstRef<STBlob>(empty);
|
||||
return Blob(b.data(), b.data() + b.size());
|
||||
}
|
||||
|
||||
AccountID
|
||||
STData::getAccountID() const
|
||||
{
|
||||
return getFieldByValue<STAccount>();
|
||||
}
|
||||
|
||||
STAmount const&
|
||||
STData::getFieldAmount() const
|
||||
{
|
||||
static STAmount const empty{};
|
||||
return getFieldByConstRef<STAmount>(empty);
|
||||
}
|
||||
|
||||
STIssue
|
||||
STData::getFieldIssue() const
|
||||
{
|
||||
static STIssue const empty{};
|
||||
return getFieldByConstRef<STIssue>(empty);
|
||||
}
|
||||
|
||||
STCurrency
|
||||
STData::getFieldCurrency() const
|
||||
{
|
||||
static STCurrency const empty{};
|
||||
return getFieldByConstRef<STCurrency>(empty);
|
||||
}
|
||||
|
||||
STNumber
|
||||
STData::getFieldNumber() const
|
||||
{
|
||||
static STNumber const empty{};
|
||||
return getFieldByConstRef<STNumber>(empty);
|
||||
}
|
||||
|
||||
STData
|
||||
dataFromJson(SField const& field, json::Value const& v)
|
||||
{
|
||||
json::Value type;
|
||||
json::Value value;
|
||||
|
||||
if (!v.isObject())
|
||||
Throw<std::runtime_error>("STData: expected object");
|
||||
|
||||
type = v[jss::type];
|
||||
value = v[jss::value];
|
||||
|
||||
if (type.isNull())
|
||||
Throw<std::runtime_error>("STData: type is null");
|
||||
if (value.isNull())
|
||||
Throw<std::runtime_error>("STData: value is null");
|
||||
|
||||
auto typeStr = type.asString();
|
||||
|
||||
if (typeStr == "UINT8")
|
||||
{
|
||||
STData data(field, static_cast<unsigned char>(value.asUInt()));
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT16")
|
||||
{
|
||||
STData data(field, static_cast<std::uint16_t>(value.asUInt()));
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT32")
|
||||
{
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
STData data(field, beast::lexicalCastThrow<std::uint32_t>(value.asString()));
|
||||
return data;
|
||||
}
|
||||
else if (value.isInt())
|
||||
{
|
||||
STData data(field, to_unsigned<std::uint32_t>(value.asInt()));
|
||||
return data;
|
||||
}
|
||||
else if (value.isUInt())
|
||||
{
|
||||
STData data(field, safeCast<std::uint32_t>(value.asUInt()));
|
||||
return data;
|
||||
}
|
||||
else
|
||||
{
|
||||
Throw<std::runtime_error>("bad type for UINT32");
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
Throw<std::runtime_error>("invalid data for UINT32");
|
||||
}
|
||||
}
|
||||
else if (typeStr == "UINT64")
|
||||
{
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
auto const str = value.asString();
|
||||
|
||||
std::uint64_t val = 0;
|
||||
|
||||
bool const useBase10 = field.shouldMeta(SField::kSmdBaseTen);
|
||||
|
||||
// if the field is amount, serialize as base 10
|
||||
auto [p, ec] =
|
||||
std::from_chars(str.data(), str.data() + str.size(), val, useBase10 ? 10 : 16);
|
||||
|
||||
if (ec != std::errc() || (p != str.data() + str.size()))
|
||||
Throw<std::invalid_argument>("STData: invalid UINT64 data");
|
||||
|
||||
STData data(field, val);
|
||||
return data;
|
||||
}
|
||||
else if (value.isInt())
|
||||
{
|
||||
STData data(field, to_unsigned<std::uint64_t>(value.asInt()));
|
||||
return data;
|
||||
}
|
||||
else if (value.isUInt())
|
||||
{
|
||||
STData data(field, safeCast<std::uint64_t>(value.asUInt()));
|
||||
return data;
|
||||
}
|
||||
else
|
||||
{
|
||||
Throw<std::runtime_error>("STData: bad type for UINT64");
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
Throw<std::runtime_error>("STData: invalid data for UINT64");
|
||||
}
|
||||
}
|
||||
else if (typeStr == "UINT128")
|
||||
{
|
||||
if (!value.isString())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: expected string for UINT128");
|
||||
}
|
||||
|
||||
uint128 num;
|
||||
|
||||
if (auto const s = value.asString(); !num.parseHex(s))
|
||||
{
|
||||
if (!s.empty())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: invalid UINT128 data");
|
||||
}
|
||||
|
||||
num.zero();
|
||||
}
|
||||
|
||||
STData data(field, num);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT192")
|
||||
{
|
||||
if (!value.isString())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: expected string for UINT192");
|
||||
}
|
||||
|
||||
uint192 num;
|
||||
|
||||
if (auto const s = value.asString(); !num.parseHex(s))
|
||||
{
|
||||
if (!s.empty())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: invalid UINT192 data");
|
||||
}
|
||||
|
||||
num.zero();
|
||||
}
|
||||
|
||||
STData data(field, num);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT160")
|
||||
{
|
||||
if (!value.isString())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: expected string for UINT160");
|
||||
}
|
||||
|
||||
uint160 num;
|
||||
|
||||
if (auto const s = value.asString(); !num.parseHex(s))
|
||||
{
|
||||
if (!s.empty())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: invalid UINT160 data");
|
||||
}
|
||||
|
||||
num.zero();
|
||||
}
|
||||
|
||||
STData data(field, num);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT256")
|
||||
{
|
||||
if (!value.isString())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: expected string for UINT256");
|
||||
}
|
||||
|
||||
uint256 num;
|
||||
|
||||
if (auto const s = value.asString(); !num.parseHex(s))
|
||||
{
|
||||
if (!s.empty())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: invalid UINT256 data");
|
||||
}
|
||||
|
||||
num.zero();
|
||||
}
|
||||
STData data(field, num);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "VL")
|
||||
{
|
||||
if (!value.isString())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: expected string for VL");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (auto vBlob = strUnHex(value.asString()))
|
||||
{
|
||||
STData data(field, *vBlob);
|
||||
return data;
|
||||
}
|
||||
else
|
||||
{
|
||||
Throw<std::invalid_argument>("invalid data");
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
Throw<std::runtime_error>("STData: invalid data");
|
||||
}
|
||||
}
|
||||
else if (typeStr == "AMOUNT")
|
||||
{
|
||||
try
|
||||
{
|
||||
STData data(field, amountFromJson(field, value));
|
||||
return data;
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
Throw<std::runtime_error>("STData: invalid data for AMOUNT");
|
||||
}
|
||||
}
|
||||
else if (typeStr == "ACCOUNT")
|
||||
{
|
||||
if (!value.isString())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: expected string for ACCOUNT");
|
||||
}
|
||||
|
||||
std::string const strValue = value.asString();
|
||||
|
||||
try
|
||||
{
|
||||
if (AccountID account; account.parseHex(strValue))
|
||||
{
|
||||
STData data(field, account);
|
||||
return data;
|
||||
}
|
||||
|
||||
if (auto result = parseBase58<AccountID>(strValue))
|
||||
{
|
||||
STData data(field, *result);
|
||||
return data;
|
||||
}
|
||||
|
||||
Throw<std::runtime_error>("STData: invalid data for ACCOUNT");
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
Throw<std::runtime_error>("STData: invalid data for ACCOUNT");
|
||||
}
|
||||
}
|
||||
else if (typeStr == "ISSUE")
|
||||
{
|
||||
try
|
||||
{
|
||||
STData data(field, issueFromJson(field, value));
|
||||
return data;
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
Throw<std::runtime_error>("STData: invalid data for ISSUE");
|
||||
}
|
||||
}
|
||||
else if (typeStr == "CURRENCY")
|
||||
{
|
||||
try
|
||||
{
|
||||
STData data(field, currencyFromJson(field, value));
|
||||
return data;
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
Throw<std::runtime_error>("STData: invalid data for CURRENCY");
|
||||
}
|
||||
}
|
||||
else if (typeStr == "NUMBER")
|
||||
{
|
||||
if (!value.isString())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: expected string for NUMBER");
|
||||
}
|
||||
|
||||
STNumber const number = numberFromJson(field, value);
|
||||
STData data(field, number);
|
||||
return data;
|
||||
}
|
||||
|
||||
// Handle unknown or unsupported type
|
||||
Throw<std::runtime_error>("STData: unsupported type string: " + typeStr);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
254
src/libxrpl/protocol/STDataType.cpp
Normal file
254
src/libxrpl/protocol/STDataType.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
#include <xrpl/protocol/STDataType.h>
|
||||
|
||||
#include <xrpl/basics/Buffer.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/StringUtilities.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STBlob.h>
|
||||
#include <xrpl/protocol/detail/STVar.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// TODO
|
||||
STDataType::STDataType(SField const& n) : STBase(n), inner_type_(STI_NOTPRESENT)
|
||||
{
|
||||
}
|
||||
|
||||
STDataType::STDataType(SField const& n, SerializedTypeID v)
|
||||
: STBase(n), inner_type_(v), default_(false)
|
||||
{
|
||||
}
|
||||
|
||||
STDataType::STDataType(SerialIter& sit, SField const& name)
|
||||
: STBase(name), inner_type_(STI_DATA), default_(false)
|
||||
{
|
||||
std::uint16_t const stype = SerializedTypeID(sit.get16());
|
||||
inner_type_ = stype;
|
||||
}
|
||||
|
||||
STBase*
|
||||
STDataType::copy(std::size_t n, void* buf) const
|
||||
{
|
||||
return emplace(n, buf, *this);
|
||||
}
|
||||
|
||||
STBase*
|
||||
STDataType::move(std::size_t n, void* buf)
|
||||
{
|
||||
return emplace(n, buf, std::move(*this));
|
||||
}
|
||||
|
||||
SerializedTypeID
|
||||
STDataType::getSType() const
|
||||
{
|
||||
return STI_DATATYPE;
|
||||
}
|
||||
|
||||
void
|
||||
STDataType::setInnerSType(SerializedTypeID v)
|
||||
{
|
||||
inner_type_ = v;
|
||||
}
|
||||
|
||||
void
|
||||
STDataType::add(Serializer& s) const
|
||||
{
|
||||
s.add16(inner_type_);
|
||||
}
|
||||
|
||||
bool
|
||||
STDataType::isEquivalent(STBase const& t) const
|
||||
{
|
||||
auto const* const tPtr = dynamic_cast<STDataType const*>(&t);
|
||||
return tPtr && (default_ == tPtr->default_) && (inner_type_ == tPtr->inner_type_);
|
||||
}
|
||||
|
||||
bool
|
||||
STDataType::isDefault() const
|
||||
{
|
||||
return default_;
|
||||
}
|
||||
|
||||
std::string
|
||||
STDataType::getInnerTypeString() const
|
||||
{
|
||||
std::string inner_type_str = "Unknown";
|
||||
// Optionally, convert inner_type_ to its string representation if mappings
|
||||
// exist
|
||||
switch (static_cast<SerializedTypeID>(inner_type_))
|
||||
{
|
||||
case STI_UINT8:
|
||||
inner_type_str = "UINT8";
|
||||
break;
|
||||
case STI_UINT16:
|
||||
inner_type_str = "UINT16";
|
||||
break;
|
||||
case STI_UINT32:
|
||||
inner_type_str = "UINT32";
|
||||
break;
|
||||
case STI_UINT64:
|
||||
inner_type_str = "UINT64";
|
||||
break;
|
||||
case STI_UINT128:
|
||||
inner_type_str = "UINT128";
|
||||
break;
|
||||
case STI_UINT160:
|
||||
inner_type_str = "UINT160";
|
||||
break;
|
||||
case STI_UINT192:
|
||||
inner_type_str = "UINT192";
|
||||
break;
|
||||
case STI_UINT256:
|
||||
inner_type_str = "UINT256";
|
||||
break;
|
||||
case STI_VL:
|
||||
inner_type_str = "VL";
|
||||
break;
|
||||
case STI_ACCOUNT:
|
||||
inner_type_str = "ACCOUNT";
|
||||
break;
|
||||
case STI_AMOUNT:
|
||||
inner_type_str = "AMOUNT";
|
||||
break;
|
||||
case STI_ISSUE:
|
||||
inner_type_str = "ISSUE";
|
||||
break;
|
||||
case STI_CURRENCY:
|
||||
inner_type_str = "CURRENCY";
|
||||
break;
|
||||
case STI_NUMBER:
|
||||
inner_type_str = "NUMBER";
|
||||
break;
|
||||
// Add other known types as needed
|
||||
default:
|
||||
inner_type_str = std::to_string(inner_type_);
|
||||
}
|
||||
|
||||
return inner_type_str;
|
||||
}
|
||||
|
||||
std::string
|
||||
STDataType::getText() const
|
||||
{
|
||||
std::string const inner_type_str = getInnerTypeString();
|
||||
return "STDataType{InnerType: " + inner_type_str + "}";
|
||||
}
|
||||
|
||||
json::Value
|
||||
STDataType::getJson(JsonOptions) const
|
||||
{
|
||||
json::Value ret(json::ValueType::Object);
|
||||
ret[jss::type] = getInnerTypeString();
|
||||
return ret;
|
||||
}
|
||||
|
||||
STDataType
|
||||
dataTypeFromJson(SField const& field, json::Value const& v)
|
||||
{
|
||||
SerializedTypeID typeId = STI_NOTPRESENT;
|
||||
json::Value type;
|
||||
json::Value const value;
|
||||
|
||||
if (!v.isObject())
|
||||
{
|
||||
Throw<std::runtime_error>("STData: expected object");
|
||||
}
|
||||
|
||||
type = v[jss::type];
|
||||
auto typeStr = type.asString();
|
||||
|
||||
if (typeStr == "UINT8")
|
||||
{
|
||||
typeId = STI_UINT8;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT16")
|
||||
{
|
||||
typeId = STI_UINT16;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT32")
|
||||
{
|
||||
typeId = STI_UINT32;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT64")
|
||||
{
|
||||
typeId = STI_UINT64;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT128")
|
||||
{
|
||||
typeId = STI_UINT128;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT160")
|
||||
{
|
||||
typeId = STI_UINT160;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT192")
|
||||
{
|
||||
typeId = STI_UINT192;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "UINT256")
|
||||
{
|
||||
typeId = STI_UINT256;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "VL")
|
||||
{
|
||||
typeId = STI_VL;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "ACCOUNT")
|
||||
{
|
||||
typeId = STI_ACCOUNT;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "AMOUNT")
|
||||
{
|
||||
typeId = STI_AMOUNT;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "ISSUE")
|
||||
{
|
||||
typeId = STI_ISSUE;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "CURRENCY")
|
||||
{
|
||||
typeId = STI_CURRENCY;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
else if (typeStr == "NUMBER")
|
||||
{
|
||||
typeId = STI_NUMBER;
|
||||
STDataType data(field, typeId);
|
||||
return data;
|
||||
}
|
||||
|
||||
// Handle unknown or unsupported type
|
||||
Throw<std::runtime_error>("STData: unsupported type string: " + typeStr);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
766
src/libxrpl/protocol/STJson.cpp
Normal file
766
src/libxrpl/protocol/STJson.cpp
Normal file
@@ -0,0 +1,766 @@
|
||||
#include <xrpl/protocol/STJson.h>
|
||||
|
||||
#include <xrpl/basics/strHex.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STArray.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
#include <xrpl/protocol/STBlob.h>
|
||||
#include <xrpl/protocol/STCurrency.h>
|
||||
#include <xrpl/protocol/STData.h>
|
||||
#include <xrpl/protocol/STDataType.h>
|
||||
#include <xrpl/protocol/STInteger.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STPathSet.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
STJson::STJson(SField const& name) : STBase{name}, data_{Map{}}
|
||||
{
|
||||
}
|
||||
|
||||
STJson::STJson(SerialIter& sit, SField const& name) : STBase{name}
|
||||
{
|
||||
if (sit.empty())
|
||||
{
|
||||
data_ = Map{};
|
||||
return;
|
||||
}
|
||||
|
||||
int length = sit.getVLDataLength();
|
||||
if (length < 0)
|
||||
Throw<std::runtime_error>("Invalid STJson length");
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
data_ = Map{};
|
||||
return;
|
||||
}
|
||||
|
||||
// Read type byte
|
||||
auto typeByte = sit.get8();
|
||||
JsonType const type = static_cast<JsonType>(typeByte);
|
||||
length--; // Account for type byte
|
||||
|
||||
int const initialBytesLeft = sit.getBytesLeft();
|
||||
|
||||
if (type == JsonType::Array)
|
||||
{
|
||||
Array array;
|
||||
while (sit.getBytesLeft() > 0 && (initialBytesLeft - sit.getBytesLeft()) < length)
|
||||
{
|
||||
auto valueVL = sit.getVL();
|
||||
if (!valueVL.empty())
|
||||
{
|
||||
SerialIter valueSit(valueVL.data(), valueVL.size());
|
||||
auto value = makeValueFromVLWithType(valueSit);
|
||||
array.push_back(std::move(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
array.push_back(nullptr);
|
||||
}
|
||||
}
|
||||
data_ = std::move(array);
|
||||
}
|
||||
else // JsonType::Object
|
||||
{
|
||||
Map map;
|
||||
while (sit.getBytesLeft() > 0 && (initialBytesLeft - sit.getBytesLeft()) < length)
|
||||
{
|
||||
auto [key, value] = parsePair(sit);
|
||||
map.emplace(std::move(key), std::move(value));
|
||||
}
|
||||
data_ = std::move(map);
|
||||
}
|
||||
|
||||
int const consumedBytes = initialBytesLeft - sit.getBytesLeft();
|
||||
if (consumedBytes != length)
|
||||
Throw<std::runtime_error>("STJson length mismatch");
|
||||
}
|
||||
|
||||
STJson::STJson(Map&& map) : data_(std::move(map))
|
||||
{
|
||||
}
|
||||
|
||||
STJson::STJson(Array&& array) : data_(std::move(array))
|
||||
{
|
||||
}
|
||||
|
||||
SerializedTypeID
|
||||
STJson::getSType() const
|
||||
{
|
||||
return STI_JSON;
|
||||
}
|
||||
|
||||
bool
|
||||
STJson::isArray() const
|
||||
{
|
||||
return std::holds_alternative<Array>(data_);
|
||||
}
|
||||
|
||||
bool
|
||||
STJson::isObject() const
|
||||
{
|
||||
return std::holds_alternative<Map>(data_);
|
||||
}
|
||||
|
||||
STJson::JsonType
|
||||
STJson::getType() const
|
||||
{
|
||||
return isArray() ? JsonType::Array : JsonType::Object;
|
||||
}
|
||||
|
||||
int
|
||||
STJson::getDepth() const
|
||||
{
|
||||
if (isArray())
|
||||
{
|
||||
auto const& array = std::get<Array>(data_);
|
||||
for (auto const& value : array)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
auto nested = std::dynamic_pointer_cast<STJson>(value);
|
||||
if (nested)
|
||||
return 1 + nested->getDepth();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else // isObject()
|
||||
{
|
||||
auto const& map = std::get<Map>(data_);
|
||||
for (auto const& [key, value] : map)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
auto nested = std::dynamic_pointer_cast<STJson>(value);
|
||||
if (nested)
|
||||
return 1 + nested->getDepth();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
STJson::validateDepth(Value const& value, int currentDepth) const
|
||||
{
|
||||
if (!value)
|
||||
return;
|
||||
|
||||
auto nested = std::dynamic_pointer_cast<STJson>(value);
|
||||
if (!nested)
|
||||
return;
|
||||
|
||||
// Adding an STJson value increases depth by 1
|
||||
int const totalDepth = currentDepth + 1 + nested->getDepth();
|
||||
if (totalDepth > 1)
|
||||
Throw<std::runtime_error>("STJson nesting depth exceeds maximum of 1");
|
||||
|
||||
// Arrays cannot contain arrays
|
||||
if (isArray() && nested->isArray())
|
||||
Throw<std::runtime_error>("STJson arrays cannot contain arrays");
|
||||
}
|
||||
|
||||
void
|
||||
STJson::setObjectField(Key const& key, Value const& value)
|
||||
{
|
||||
if (!isObject())
|
||||
Throw<std::runtime_error>("STJson::setObjectField called on non-object");
|
||||
validateDepth(value, 0);
|
||||
std::get<Map>(data_)[key] = value;
|
||||
}
|
||||
|
||||
std::shared_ptr<STJson>
|
||||
STJson::fromBlob(void const* data, std::size_t size)
|
||||
{
|
||||
SerialIter sit(static_cast<uint8_t const*>(data), size);
|
||||
return fromSerialIter(sit);
|
||||
}
|
||||
|
||||
std::shared_ptr<STJson>
|
||||
STJson::fromSerialIter(SerialIter& sit)
|
||||
{
|
||||
if (sit.empty())
|
||||
return nullptr;
|
||||
|
||||
int length = sit.getVLDataLength();
|
||||
if (length < 0)
|
||||
Throw<std::runtime_error>("Invalid STJson length");
|
||||
|
||||
if (length == 0)
|
||||
return std::make_shared<STJson>(Map{});
|
||||
|
||||
// Read type byte
|
||||
auto typeByte = sit.get8();
|
||||
JsonType const type = static_cast<JsonType>(typeByte);
|
||||
length--; // Account for type byte
|
||||
|
||||
int const initialBytesLeft = sit.getBytesLeft();
|
||||
|
||||
if (type == JsonType::Array)
|
||||
{
|
||||
Array array;
|
||||
while (sit.getBytesLeft() > 0 && (initialBytesLeft - sit.getBytesLeft()) < length)
|
||||
{
|
||||
auto valueVL = sit.getVL();
|
||||
if (!valueVL.empty())
|
||||
{
|
||||
SerialIter valueSit(valueVL.data(), valueVL.size());
|
||||
auto value = makeValueFromVLWithType(valueSit);
|
||||
array.push_back(std::move(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
array.push_back(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
int const consumedBytes = initialBytesLeft - sit.getBytesLeft();
|
||||
if (consumedBytes != length)
|
||||
Throw<std::runtime_error>("STJson length mismatch");
|
||||
|
||||
return std::make_shared<STJson>(std::move(array));
|
||||
}
|
||||
else // JsonType::Object
|
||||
{
|
||||
Map map;
|
||||
while (sit.getBytesLeft() > 0 && (initialBytesLeft - sit.getBytesLeft()) < length)
|
||||
{
|
||||
auto [key, value] = parsePair(sit);
|
||||
map.emplace(std::move(key), std::move(value));
|
||||
}
|
||||
|
||||
int const consumedBytes = initialBytesLeft - sit.getBytesLeft();
|
||||
if (consumedBytes != length)
|
||||
Throw<std::runtime_error>("STJson length mismatch");
|
||||
|
||||
return std::make_shared<STJson>(std::move(map));
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<STJson::Key, STJson::Value>
|
||||
STJson::parsePair(SerialIter& sit)
|
||||
{
|
||||
auto keyBlob = sit.getVL();
|
||||
std::string key(reinterpret_cast<char const*>(keyBlob.data()), keyBlob.size());
|
||||
auto valueVL = sit.getVL();
|
||||
if (valueVL.empty())
|
||||
return {std::move(key), nullptr};
|
||||
|
||||
SerialIter valueSit(valueVL.data(), valueVL.size());
|
||||
auto value = makeValueFromVLWithType(valueSit);
|
||||
|
||||
return {std::move(key), std::move(value)};
|
||||
}
|
||||
|
||||
STJson::Array
|
||||
STJson::parseArray(SerialIter& sit, int length)
|
||||
{
|
||||
Array array;
|
||||
int const initialBytesLeft = sit.getBytesLeft();
|
||||
|
||||
while (sit.getBytesLeft() > 0 && (initialBytesLeft - sit.getBytesLeft()) < length)
|
||||
{
|
||||
auto valueVL = sit.getVL();
|
||||
if (!valueVL.empty())
|
||||
{
|
||||
SerialIter valueSit(valueVL.data(), valueVL.size());
|
||||
auto value = makeValueFromVLWithType(valueSit);
|
||||
array.push_back(std::move(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
array.push_back(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
STJson::Value
|
||||
STJson::makeValueFromVLWithType(SerialIter& sit)
|
||||
{
|
||||
if (sit.getBytesLeft() == 0)
|
||||
return nullptr;
|
||||
|
||||
// Read SType marker (1 byte)
|
||||
auto typeCode = sit.get8();
|
||||
SerializedTypeID const stype = static_cast<SerializedTypeID>(typeCode);
|
||||
|
||||
// Dispatch to correct SType
|
||||
switch (stype)
|
||||
{
|
||||
case STI_UINT8:
|
||||
return std::make_shared<STUInt8>(sfCloseResolution, sit.get8());
|
||||
case STI_UINT16:
|
||||
return std::make_shared<STUInt16>(sfSignerWeight, sit.get16());
|
||||
case STI_UINT32:
|
||||
return std::make_shared<STUInt32>(sfNetworkID, sit.get32());
|
||||
case STI_UINT64:
|
||||
return std::make_shared<STUInt64>(sfIndexNext, sit.get64());
|
||||
case STI_UINT128:
|
||||
return std::make_shared<STUInt128>(sfEmailHash, sit.get128());
|
||||
case STI_UINT160:
|
||||
return std::make_shared<STUInt160>(sfTakerPaysCurrency, sit.get160());
|
||||
case STI_UINT192:
|
||||
return std::make_shared<STUInt192>(sfMPTokenIssuanceID, sit.get192());
|
||||
case STI_UINT256:
|
||||
return std::make_shared<STUInt256>(sfLedgerHash, sit.get256());
|
||||
case STI_VL: {
|
||||
auto blob = sit.getVL();
|
||||
return std::make_shared<STBlob>(sfData, blob.data(), blob.size());
|
||||
}
|
||||
case STI_ACCOUNT:
|
||||
return std::make_shared<STAccount>(sit, sfAccount);
|
||||
case STI_AMOUNT:
|
||||
return std::make_shared<STAmount>(sit, sfAmount);
|
||||
// case STI_NUMBER:
|
||||
// return std::make_shared<STNumber>(sit, sfNumber);
|
||||
case STI_ISSUE:
|
||||
return std::make_shared<STIssue>(sit, sfAsset);
|
||||
case STI_CURRENCY:
|
||||
return std::make_shared<STCurrency>(sit, sfBaseAsset);
|
||||
case STI_JSON:
|
||||
return std::make_shared<STJson>(sit, sfContractJson);
|
||||
case STI_OBJECT:
|
||||
case STI_ARRAY:
|
||||
case STI_PATHSET:
|
||||
case STI_VECTOR256:
|
||||
default:
|
||||
// Unknown type, treat as blob
|
||||
{
|
||||
auto blob = sit.getSlice(sit.getBytesLeft());
|
||||
return std::make_shared<STBlob>(sfData, blob.data(), blob.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<STJson::Value>
|
||||
STJson::getObjectField(Key const& key) const
|
||||
{
|
||||
if (!isObject())
|
||||
return std::nullopt;
|
||||
|
||||
auto const& map = std::get<Map>(data_);
|
||||
auto it = map.find(key);
|
||||
if (it == map.end() || !it->second)
|
||||
return std::nullopt;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void
|
||||
STJson::setNestedObjectField(Key const& key, Key const& nestedKey, Value const& value)
|
||||
{
|
||||
if (!isObject())
|
||||
Throw<std::runtime_error>("STJson::setNestedObjectField called on non-object");
|
||||
|
||||
validateDepth(value, 1); // We're at depth 1 (nested)
|
||||
|
||||
auto& map = std::get<Map>(data_);
|
||||
auto it = map.find(key);
|
||||
std::shared_ptr<STJson> nested;
|
||||
if (it == map.end() || !it->second)
|
||||
{
|
||||
// Create new nested STJson
|
||||
nested = std::make_shared<STJson>();
|
||||
map[key] = nested;
|
||||
}
|
||||
else
|
||||
{
|
||||
nested = std::dynamic_pointer_cast<STJson>(it->second);
|
||||
if (!nested)
|
||||
{
|
||||
// Overwrite with new STJson if not an STJson
|
||||
nested = std::make_shared<STJson>();
|
||||
map[key] = nested;
|
||||
}
|
||||
}
|
||||
nested->setObjectField(nestedKey, value);
|
||||
}
|
||||
|
||||
std::optional<STJson::Value>
|
||||
STJson::getNestedObjectField(Key const& key, Key const& nestedKey) const
|
||||
{
|
||||
if (!isObject())
|
||||
return std::nullopt;
|
||||
|
||||
auto const& map = std::get<Map>(data_);
|
||||
auto it = map.find(key);
|
||||
if (it == map.end() || !it->second)
|
||||
return std::nullopt;
|
||||
auto nested = std::dynamic_pointer_cast<STJson>(it->second);
|
||||
if (!nested)
|
||||
return std::nullopt;
|
||||
return nested->getObjectField(nestedKey);
|
||||
}
|
||||
|
||||
STJson::Map const&
|
||||
STJson::getMap() const
|
||||
{
|
||||
if (!isObject())
|
||||
Throw<std::runtime_error>("STJson::getMap called on non-object");
|
||||
return std::get<Map>(data_);
|
||||
}
|
||||
|
||||
STJson::Array const&
|
||||
STJson::getArray() const
|
||||
{
|
||||
if (!isArray())
|
||||
Throw<std::runtime_error>("STJson::getArray called on non-array");
|
||||
return std::get<Array>(data_);
|
||||
}
|
||||
|
||||
void
|
||||
STJson::pushArrayElement(Value const& value)
|
||||
{
|
||||
if (!isArray())
|
||||
Throw<std::runtime_error>("STJson::pushArrayElement called on non-array");
|
||||
validateDepth(value, 0);
|
||||
std::get<Array>(data_).push_back(value);
|
||||
}
|
||||
|
||||
std::optional<STJson::Value>
|
||||
STJson::getArrayElement(size_t index) const
|
||||
{
|
||||
if (!isArray())
|
||||
return std::nullopt;
|
||||
|
||||
auto const& array = std::get<Array>(data_);
|
||||
if (index >= array.size())
|
||||
return std::nullopt;
|
||||
|
||||
return array[index];
|
||||
}
|
||||
|
||||
void
|
||||
STJson::setArrayElement(size_t index, Value const& value)
|
||||
{
|
||||
if (!isArray())
|
||||
Throw<std::runtime_error>("STJson::setArrayElement called on non-array");
|
||||
validateDepth(value, 0);
|
||||
|
||||
auto& array = std::get<Array>(data_);
|
||||
// Auto-resize with nulls if needed
|
||||
if (index >= array.size())
|
||||
array.resize(index + 1, nullptr);
|
||||
|
||||
array[index] = value;
|
||||
}
|
||||
|
||||
void
|
||||
STJson::setArrayElementField(size_t index, Key const& key, Value const& value)
|
||||
{
|
||||
if (!isArray())
|
||||
Throw<std::runtime_error>("STJson::setArrayElementField called on non-array");
|
||||
|
||||
validateDepth(value, 1); // We're at depth 1 (inside array element)
|
||||
|
||||
auto& array = std::get<Array>(data_);
|
||||
// Auto-resize with nulls if needed
|
||||
if (index >= array.size())
|
||||
array.resize(index + 1, nullptr);
|
||||
|
||||
// Get or create STJson object at index
|
||||
std::shared_ptr<STJson> element;
|
||||
if (!array[index])
|
||||
{
|
||||
element = std::make_shared<STJson>(Map{});
|
||||
array[index] = element;
|
||||
}
|
||||
else
|
||||
{
|
||||
element = std::dynamic_pointer_cast<STJson>(array[index]);
|
||||
if (!element)
|
||||
{
|
||||
// Replace with new STJson if not an STJson
|
||||
element = std::make_shared<STJson>(Map{});
|
||||
array[index] = element;
|
||||
}
|
||||
}
|
||||
|
||||
element->setObjectField(key, value);
|
||||
}
|
||||
|
||||
std::optional<STJson::Value>
|
||||
STJson::getArrayElementField(size_t index, Key const& key) const
|
||||
{
|
||||
if (!isArray())
|
||||
return std::nullopt;
|
||||
|
||||
auto const& array = std::get<Array>(data_);
|
||||
if (index >= array.size())
|
||||
return std::nullopt;
|
||||
|
||||
auto element = std::dynamic_pointer_cast<STJson>(array[index]);
|
||||
if (!element)
|
||||
return std::nullopt;
|
||||
|
||||
return element->getObjectField(key);
|
||||
}
|
||||
|
||||
size_t
|
||||
STJson::arraySize() const
|
||||
{
|
||||
if (!isArray())
|
||||
return 0;
|
||||
return std::get<Array>(data_).size();
|
||||
}
|
||||
|
||||
void
|
||||
STJson::setNestedArrayElement(Key const& key, size_t index, Value const& value)
|
||||
{
|
||||
if (!isObject())
|
||||
Throw<std::runtime_error>("STJson::setNestedArrayElement called on non-object");
|
||||
|
||||
validateDepth(value, 1); // We're at depth 1 (nested array)
|
||||
|
||||
auto& map = std::get<Map>(data_);
|
||||
auto it = map.find(key);
|
||||
std::shared_ptr<STJson> arrayJson;
|
||||
|
||||
if (it == map.end() || !it->second)
|
||||
{
|
||||
// Create new nested STJson array
|
||||
arrayJson = std::make_shared<STJson>(Array{});
|
||||
map[key] = arrayJson;
|
||||
}
|
||||
else
|
||||
{
|
||||
arrayJson = std::dynamic_pointer_cast<STJson>(it->second);
|
||||
if (!arrayJson)
|
||||
{
|
||||
// Replace with new STJson array if not an STJson
|
||||
arrayJson = std::make_shared<STJson>(Array{});
|
||||
map[key] = arrayJson;
|
||||
}
|
||||
else if (!arrayJson->isArray())
|
||||
{
|
||||
// Replace with array if not an array
|
||||
arrayJson = std::make_shared<STJson>(Array{});
|
||||
map[key] = arrayJson;
|
||||
}
|
||||
}
|
||||
|
||||
arrayJson->setArrayElement(index, value);
|
||||
}
|
||||
|
||||
void
|
||||
STJson::setNestedArrayElementField(
|
||||
Key const& key,
|
||||
size_t index,
|
||||
Key const& nestedKey,
|
||||
Value const& value)
|
||||
{
|
||||
if (!isObject())
|
||||
Throw<std::runtime_error>("STJson::setNestedArrayElementField called on non-object");
|
||||
|
||||
validateDepth(value, 1); // We're at depth 1 (nested array element field -
|
||||
// still counts as depth 1)
|
||||
|
||||
auto& map = std::get<Map>(data_);
|
||||
auto it = map.find(key);
|
||||
std::shared_ptr<STJson> arrayJson;
|
||||
|
||||
if (it == map.end() || !it->second)
|
||||
{
|
||||
// Create new nested STJson array
|
||||
arrayJson = std::make_shared<STJson>(Array{});
|
||||
map[key] = arrayJson;
|
||||
}
|
||||
else
|
||||
{
|
||||
arrayJson = std::dynamic_pointer_cast<STJson>(it->second);
|
||||
if (!arrayJson)
|
||||
{
|
||||
// Replace with new STJson array if not an STJson
|
||||
arrayJson = std::make_shared<STJson>(Array{});
|
||||
map[key] = arrayJson;
|
||||
}
|
||||
else if (!arrayJson->isArray())
|
||||
{
|
||||
// Replace with array if not an array
|
||||
arrayJson = std::make_shared<STJson>(Array{});
|
||||
map[key] = arrayJson;
|
||||
}
|
||||
}
|
||||
|
||||
arrayJson->setArrayElementField(index, nestedKey, value);
|
||||
}
|
||||
|
||||
std::optional<STJson::Value>
|
||||
STJson::getNestedArrayElement(Key const& key, size_t index) const
|
||||
{
|
||||
if (!isObject())
|
||||
return std::nullopt;
|
||||
|
||||
auto const& map = std::get<Map>(data_);
|
||||
auto it = map.find(key);
|
||||
if (it == map.end() || !it->second)
|
||||
return std::nullopt;
|
||||
|
||||
auto arrayJson = std::dynamic_pointer_cast<STJson>(it->second);
|
||||
if (!arrayJson || !arrayJson->isArray())
|
||||
return std::nullopt;
|
||||
|
||||
return arrayJson->getArrayElement(index);
|
||||
}
|
||||
|
||||
std::optional<STJson::Value>
|
||||
STJson::getNestedArrayElementField(Key const& key, size_t index, Key const& nestedKey) const
|
||||
{
|
||||
if (!isObject())
|
||||
return std::nullopt;
|
||||
|
||||
auto const& map = std::get<Map>(data_);
|
||||
auto it = map.find(key);
|
||||
if (it == map.end() || !it->second)
|
||||
return std::nullopt;
|
||||
|
||||
auto arrayJson = std::dynamic_pointer_cast<STJson>(it->second);
|
||||
if (!arrayJson || !arrayJson->isArray())
|
||||
return std::nullopt;
|
||||
|
||||
return arrayJson->getArrayElementField(index, nestedKey);
|
||||
}
|
||||
|
||||
void
|
||||
STJson::addVLKey(Serializer& s, std::string const& str)
|
||||
{
|
||||
s.addVL(str.data(), str.size());
|
||||
}
|
||||
|
||||
void
|
||||
STJson::addVLValue(Serializer& s, std::shared_ptr<STBase> const& value)
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
s.addVL(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
Serializer tmp;
|
||||
tmp.add8(static_cast<uint8_t>(value->getSType()));
|
||||
value->add(tmp);
|
||||
s.addVL(tmp.peekData().data(), tmp.peekData().size());
|
||||
}
|
||||
|
||||
void
|
||||
STJson::add(Serializer& s) const
|
||||
{
|
||||
Serializer inner;
|
||||
|
||||
// Add type byte
|
||||
inner.add8(static_cast<uint8_t>(getType()));
|
||||
|
||||
if (isArray())
|
||||
{
|
||||
auto const& array = std::get<Array>(data_);
|
||||
for (auto const& value : array)
|
||||
{
|
||||
addVLValue(inner, value);
|
||||
}
|
||||
}
|
||||
else // isObject()
|
||||
{
|
||||
auto const& map = std::get<Map>(data_);
|
||||
for (auto const& [key, value] : map)
|
||||
{
|
||||
addVLKey(inner, key);
|
||||
addVLValue(inner, value);
|
||||
}
|
||||
}
|
||||
|
||||
s.addVL(inner.peekData().data(), inner.peekData().size());
|
||||
}
|
||||
|
||||
json::Value
|
||||
STJson::getJson(JsonOptions options) const
|
||||
{
|
||||
if (isArray())
|
||||
{
|
||||
json::Value arr(json::ValueType::Array);
|
||||
auto const& array = std::get<Array>(data_);
|
||||
for (auto const& value : array)
|
||||
{
|
||||
if (value)
|
||||
arr.append(value->getJson(options));
|
||||
else
|
||||
arr.append(json::ValueType::Null);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
else // isObject()
|
||||
{
|
||||
json::Value obj(json::ValueType::Object);
|
||||
auto const& map = std::get<Map>(data_);
|
||||
for (auto const& [key, value] : map)
|
||||
{
|
||||
auto const hexKey = strHex(key);
|
||||
if (value)
|
||||
obj[hexKey] = value->getJson(options);
|
||||
else
|
||||
obj[hexKey] = json::ValueType::Null;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
STJson::isEquivalent(STBase const& t) const
|
||||
{
|
||||
auto const* const tPtr = dynamic_cast<STJson const*>(&t);
|
||||
return tPtr && (data_ == tPtr->data_);
|
||||
}
|
||||
|
||||
bool
|
||||
STJson::isDefault() const
|
||||
{
|
||||
return default_;
|
||||
}
|
||||
|
||||
Blob
|
||||
STJson::toBlob() const
|
||||
{
|
||||
Serializer s;
|
||||
add(s);
|
||||
return s.peekData();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
STJson::size() const
|
||||
{
|
||||
Serializer s;
|
||||
add(s);
|
||||
return s.size();
|
||||
}
|
||||
|
||||
void
|
||||
STJson::setValue(STJson const& v)
|
||||
{
|
||||
data_ = v.data_;
|
||||
}
|
||||
|
||||
STBase*
|
||||
STJson::copy(std::size_t n, void* buf) const
|
||||
{
|
||||
return emplace(n, buf, *this);
|
||||
}
|
||||
|
||||
STBase*
|
||||
STJson::move(std::size_t n, void* buf)
|
||||
{
|
||||
return emplace(n, buf, std::move(*this));
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -21,8 +21,11 @@
|
||||
#include <xrpl/protocol/STBitString.h>
|
||||
#include <xrpl/protocol/STBlob.h>
|
||||
#include <xrpl/protocol/STCurrency.h>
|
||||
#include <xrpl/protocol/STData.h>
|
||||
#include <xrpl/protocol/STDataType.h>
|
||||
#include <xrpl/protocol/STInteger.h>
|
||||
#include <xrpl/protocol/STIssue.h>
|
||||
#include <xrpl/protocol/STJson.h>
|
||||
#include <xrpl/protocol/STNumber.h>
|
||||
#include <xrpl/protocol/STPathSet.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
@@ -645,6 +648,20 @@ STObject::getAccountID(SField const& field) const
|
||||
return getFieldByValue<STAccount>(field);
|
||||
}
|
||||
|
||||
STData
|
||||
STObject::getFieldData(SField const& field) const
|
||||
{
|
||||
static STData const empty{field};
|
||||
return getFieldByConstRef<STData>(field, empty);
|
||||
}
|
||||
|
||||
STDataType
|
||||
STObject::getFieldDataType(SField const& field) const
|
||||
{
|
||||
static STDataType const empty{field};
|
||||
return getFieldByConstRef<STDataType>(field, empty);
|
||||
}
|
||||
|
||||
Blob
|
||||
STObject::getFieldVL(SField const& field) const
|
||||
{
|
||||
@@ -705,6 +722,13 @@ STObject::getFieldNumber(SField const& field) const
|
||||
return getFieldByConstRef<STNumber>(field, kEmpty);
|
||||
}
|
||||
|
||||
STJson const&
|
||||
STObject::getFieldJson(SField const& field) const
|
||||
{
|
||||
static STJson const empty{field};
|
||||
return getFieldByConstRef<STJson>(field, empty);
|
||||
}
|
||||
|
||||
void
|
||||
STObject::set(std::unique_ptr<STBase> v)
|
||||
{
|
||||
@@ -727,6 +751,72 @@ STObject::set(STBase&& v)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
STObject::addFieldFromSlice(SField const& sfield, Slice const& data)
|
||||
{
|
||||
SerialIter sit(data.data(), data.size());
|
||||
std::unique_ptr<STBase> element;
|
||||
|
||||
switch (sfield.fieldType)
|
||||
{
|
||||
case STI_AMOUNT:
|
||||
element = std::make_unique<STAmount>(sit, sfield);
|
||||
break;
|
||||
case STI_ACCOUNT:
|
||||
element = std::make_unique<STAccount>(sit, sfield);
|
||||
break;
|
||||
case STI_UINT8:
|
||||
element = std::make_unique<STUInt8>(sit, sfield);
|
||||
break;
|
||||
case STI_UINT16:
|
||||
element = std::make_unique<STUInt16>(sit, sfield);
|
||||
break;
|
||||
case STI_UINT32:
|
||||
element = std::make_unique<STUInt32>(sit, sfield);
|
||||
break;
|
||||
case STI_UINT64:
|
||||
element = std::make_unique<STUInt64>(sit, sfield);
|
||||
break;
|
||||
case STI_UINT128:
|
||||
element = std::make_unique<STUInt128>(sit, sfield);
|
||||
break;
|
||||
case STI_UINT160:
|
||||
element = std::make_unique<STUInt160>(sit, sfield);
|
||||
break;
|
||||
case STI_UINT192:
|
||||
element = std::make_unique<STUInt192>(sit, sfield);
|
||||
break;
|
||||
case STI_UINT256:
|
||||
element = std::make_unique<STUInt256>(sit, sfield);
|
||||
break;
|
||||
case STI_VECTOR256:
|
||||
element = std::make_unique<STVector256>(sit, sfield);
|
||||
break;
|
||||
case STI_VL:
|
||||
element = std::make_unique<STBlob>(sit, sfield);
|
||||
break;
|
||||
case STI_CURRENCY:
|
||||
element = std::make_unique<STCurrency>(sit, sfield);
|
||||
break;
|
||||
case STI_ISSUE:
|
||||
element = std::make_unique<STIssue>(sit, sfield);
|
||||
break;
|
||||
case STI_PATHSET:
|
||||
element = std::make_unique<STPathSet>(sit, sfield);
|
||||
break;
|
||||
case STI_ARRAY:
|
||||
element = std::make_unique<STArray>(sit, sfield);
|
||||
break;
|
||||
case STI_OBJECT:
|
||||
element = std::make_unique<STObject>(sit, sfield, 0);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unsupported SField type");
|
||||
}
|
||||
|
||||
this->set(std::move(element));
|
||||
}
|
||||
|
||||
void
|
||||
STObject::setFieldU8(SField const& field, unsigned char v)
|
||||
{
|
||||
@@ -841,6 +931,12 @@ STObject::setFieldObject(SField const& field, STObject const& v)
|
||||
setFieldUsingAssignment(field, v);
|
||||
}
|
||||
|
||||
void
|
||||
STObject::setFieldJson(SField const& field, STJson const& v)
|
||||
{
|
||||
setFieldUsingAssignment(field, v);
|
||||
}
|
||||
|
||||
json::Value
|
||||
STObject::getJson(JsonOptions options) const
|
||||
{
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <xrpl/protocol/STBitString.h>
|
||||
#include <xrpl/protocol/STBlob.h>
|
||||
#include <xrpl/protocol/STCurrency.h>
|
||||
#include <xrpl/protocol/STData.h>
|
||||
#include <xrpl/protocol/STDataType.h>
|
||||
#include <xrpl/protocol/STInteger.h>
|
||||
#include <xrpl/protocol/STIssue.h>
|
||||
#include <xrpl/protocol/STNumber.h>
|
||||
@@ -980,6 +982,52 @@ parseLeaf(
|
||||
}
|
||||
break;
|
||||
|
||||
case STI_DATA: {
|
||||
try
|
||||
{
|
||||
ret = detail::makeStvar<STData>(dataFromJson(field, value));
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
std::cout << "STI_DATA failed for field: " << fieldName
|
||||
<< " in object: " << jsonName << "\n";
|
||||
error = invalidData(jsonName, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case STI_DATATYPE: {
|
||||
try
|
||||
{
|
||||
ret = detail::makeStvar<STDataType>(dataTypeFromJson(field, value));
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
std::cout << "STI_DATATYPE failed for field: " << fieldName
|
||||
<< " in object: " << jsonName << "\n";
|
||||
error = invalidData(jsonName, fieldName);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STI_JSON:
|
||||
Throw<std::runtime_error>("STI_JSON is not supported");
|
||||
// try
|
||||
// {
|
||||
// ret = detail::makeStvar<STDataType>(
|
||||
// dataTypeFromJson(field, value));
|
||||
// }
|
||||
// catch (std::exception const&)
|
||||
// {
|
||||
// std::cout << "STI_DATATYPE failed for field: " << fieldName
|
||||
// << " in object: " << jsonName << "\n";
|
||||
// error = invalidData(jsonName, fieldName);
|
||||
// return ret;
|
||||
// }
|
||||
break;
|
||||
|
||||
default:
|
||||
error = badType(jsonName, fieldName);
|
||||
return ret;
|
||||
|
||||
@@ -59,6 +59,10 @@ STValidation::validationFormat()
|
||||
{sfBaseFeeDrops, SoeOptional},
|
||||
{sfReserveBaseDrops, SoeOptional},
|
||||
{sfReserveIncrementDrops, SoeOptional},
|
||||
// featureSmartEscrow
|
||||
{sfGasLimit, SoeOptional},
|
||||
{sfBytecodeSizeLimit, SoeOptional},
|
||||
{sfGasPrice, SoeOptional},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
#include <xrpl/protocol/STBitString.h>
|
||||
#include <xrpl/protocol/STBlob.h>
|
||||
#include <xrpl/protocol/STCurrency.h>
|
||||
#include <xrpl/protocol/STData.h>
|
||||
#include <xrpl/protocol/STDataType.h>
|
||||
#include <xrpl/protocol/STInteger.h>
|
||||
#include <xrpl/protocol/STIssue.h>
|
||||
#include <xrpl/protocol/STJson.h>
|
||||
#include <xrpl/protocol/STNumber.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STPathSet.h>
|
||||
@@ -223,6 +226,15 @@ STVar::constructST(SerializedTypeID id, int depth, Args&&... args)
|
||||
case STI_CURRENCY:
|
||||
construct<STCurrency>(std::forward<Args>(args)...);
|
||||
return;
|
||||
case STI_DATA:
|
||||
construct<STData>(std::forward<Args>(args)...);
|
||||
return;
|
||||
case STI_DATATYPE:
|
||||
construct<STDataType>(std::forward<Args>(args)...);
|
||||
return;
|
||||
case STI_JSON:
|
||||
construct<STJson>(std::forward<Args>(args)...);
|
||||
return;
|
||||
default:
|
||||
Throw<std::runtime_error>("Unknown object type");
|
||||
}
|
||||
|
||||
@@ -108,6 +108,9 @@ transResults()
|
||||
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
|
||||
MAKE_ERROR(tecBAD_PROOF, "Proof cannot be verified"),
|
||||
MAKE_ERROR(tecNO_SPONSOR_PERMISSION, "Sponsor has not authorized this transaction."),
|
||||
MAKE_ERROR(tecOUT_OF_GAS, "The WASM code ran out of gas during execution."),
|
||||
MAKE_ERROR(tecBYTECODE_REJECTED, "The custom WASM code that was run rejected your transaction."),
|
||||
MAKE_ERROR(tecINVALID_PARAMETERS, "Contract parameters do not match the expected ABI."),
|
||||
|
||||
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
|
||||
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
|
||||
@@ -133,6 +136,8 @@ transResults()
|
||||
MAKE_ERROR(tefINVALID_LEDGER_FIX_TYPE, "The LedgerFixType field has an invalid value."),
|
||||
MAKE_ERROR(tefNO_DST_PARTIAL, "Partial payment to create account not allowed."),
|
||||
MAKE_ERROR(tefBAD_PATH_COUNT, "Malformed: Too many paths."),
|
||||
MAKE_ERROR(tefNO_BYTECODE, "There is no WASM code to run, but a WASM-specific field was included."),
|
||||
MAKE_ERROR(tefBYTECODE_NOT_INCLUDED, "WASM code requires a field to be included that was not included."),
|
||||
|
||||
MAKE_ERROR(telLOCAL_ERROR, "Local failure."),
|
||||
MAKE_ERROR(telBAD_DOMAIN, "Domain too long."),
|
||||
@@ -204,6 +209,9 @@ transResults()
|
||||
MAKE_ERROR(temBAD_TRANSFER_FEE, "Malformed: Transfer fee is outside valid range."),
|
||||
MAKE_ERROR(temINVALID_INNER_BATCH, "Malformed: Invalid inner batch transaction."),
|
||||
MAKE_ERROR(temBAD_CIPHERTEXT, "Malformed: Invalid ciphertext."),
|
||||
MAKE_ERROR(temBAD_WASM, "Malformed: Provided WASM code is invalid."),
|
||||
MAKE_ERROR(temINVALID_BYTECODE, "Malformed: Provided WASM code is invalid."),
|
||||
MAKE_ERROR(temTEMP_DISABLED, "The transaction requires logic that is currently temporarily disabled."),
|
||||
|
||||
MAKE_ERROR(terRETRY, "Retry transaction."),
|
||||
MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."),
|
||||
|
||||
@@ -45,7 +45,7 @@ TxFormats::TxFormats()
|
||||
#undef TRANSACTION
|
||||
|
||||
#define UNWRAP(...) __VA_ARGS__
|
||||
#define TRANSACTION(tag, value, name, delegable, amendment, privileges, fields) \
|
||||
#define TRANSACTION(tag, value, name, delegatable, amendment, privileges, emitable, fields) \
|
||||
add(jss::name, tag, UNWRAP fields, getCommonFields());
|
||||
|
||||
#include <xrpl/protocol/detail/transactions.macro>
|
||||
|
||||
@@ -194,6 +194,12 @@ TxMeta::getAsObject() const
|
||||
if (parentBatchID_.has_value())
|
||||
metaData.setFieldH256(sfParentBatchID, *parentBatchID_);
|
||||
|
||||
if (gasUsed_.has_value())
|
||||
metaData.setFieldU32(sfGasUsed, *gasUsed_);
|
||||
|
||||
if (vmReturnCode_.has_value())
|
||||
metaData.setFieldI32(sfVMReturnCode, *vmReturnCode_);
|
||||
|
||||
return metaData;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ InfoSub::~InfoSub()
|
||||
safeUnsub(seq_, [&] { source_.unsubValidations(seq_); }, j);
|
||||
safeUnsub(seq_, [&] { source_.unsubPeerStatus(seq_); }, j);
|
||||
safeUnsub(seq_, [&] { source_.unsubConsensus(seq_); }, j);
|
||||
safeUnsub(seq_, [&] { source_.unsubContractEvent(seq_); }, j);
|
||||
|
||||
// Book subscriptions are torn down inline here, keyed on seq_, rather than
|
||||
// through the chunked account cleanup below. The book set is not capped, so
|
||||
|
||||
@@ -46,20 +46,40 @@ ApplyContext::ApplyContext(
|
||||
XRPL_ASSERT(
|
||||
parentBatchId.has_value() == ((flags_ & TapBatch) == TapBatch),
|
||||
"Parent Batch ID should be set if batch apply flag is set");
|
||||
view_.emplace(&base_, flags_);
|
||||
view_.emplace(&base_.view(), flags_);
|
||||
}
|
||||
|
||||
void
|
||||
ApplyContext::discard()
|
||||
{
|
||||
view_.emplace(&base_, flags_);
|
||||
base_.discard();
|
||||
view_.emplace(&base_.view(), flags_);
|
||||
}
|
||||
|
||||
void
|
||||
ApplyContext::finalize()
|
||||
{
|
||||
base_.commit();
|
||||
view_.emplace(&base_.view(), flags_);
|
||||
}
|
||||
|
||||
std::optional<TxMeta>
|
||||
ApplyContext::apply(TER ter)
|
||||
{
|
||||
// tecINTERNAL reports an xrpld bug, not a result: nothing the VM recorded
|
||||
// before we hit it belongs in the metadata.
|
||||
if (ter != tecINTERNAL)
|
||||
{
|
||||
if (vmReturnCode_.has_value())
|
||||
{
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access) view_ emplaced in constructor
|
||||
view_->setVMReturnCode(*vmReturnCode_);
|
||||
}
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access) view_ emplaced in constructor
|
||||
view_->setGasUsed(gasUsed_);
|
||||
}
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access) view_ emplaced in constructor
|
||||
return view_->apply(base_, tx, ter, parentBatchId_, (flags_ & TapDryRun) != 0u, journal);
|
||||
return view_->apply(base_.view(), tx, ter, parentBatchId_, (flags_ & TapDryRun) != 0u, journal);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
@@ -72,7 +92,7 @@ void
|
||||
ApplyContext::visit(
|
||||
std::function<void(uint256 const&, bool, SLE::const_ref, SLE::const_ref)> const& func)
|
||||
{
|
||||
view_->visit(base_, func); // NOLINT(bugprone-unchecked-optional-access)
|
||||
view_->visit(base_.view(), func); // NOLINT(bugprone-unchecked-optional-access)
|
||||
}
|
||||
|
||||
TER
|
||||
|
||||
@@ -1284,6 +1284,23 @@ removeDeletedTrustLines(
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
modifyWasmDataFields(
|
||||
ApplyView& view,
|
||||
std::vector<std::pair<uint256, SLE::const_pointer>> const& wasmObjects,
|
||||
beast::Journal viewJ)
|
||||
{
|
||||
for (auto const& [index, after] : wasmObjects)
|
||||
{
|
||||
if (auto const sle = view.peek(keylet::escrow(index)))
|
||||
{
|
||||
auto const data = after->getFieldVL(sfData);
|
||||
sle->setFieldVL(sfData, data);
|
||||
view.update(sle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the context, discarding any changes made and adjust the fee.
|
||||
*
|
||||
@@ -1336,6 +1353,8 @@ Transactor::reset(XRPAmount fee)
|
||||
}
|
||||
|
||||
// balance should have already been checked in checkFee / preFlight.
|
||||
// For batch/inner transactions (fee == 0), the balance can
|
||||
// legitimately be zero (e.g. contract pseudo-accounts).
|
||||
XRPL_ASSERT(
|
||||
(fee == beast::kZero || balance != beast::kZero) && (!view().open() || balance >= fee),
|
||||
"xrpl::Transactor::reset : valid balance");
|
||||
@@ -1451,6 +1470,10 @@ Transactor::processPersistentChanges(TER result, XRPAmount fee)
|
||||
types.insert(ltNFTOKEN_OFFER);
|
||||
types.insert(ltCREDENTIAL);
|
||||
}
|
||||
else if (ter == tecBYTECODE_REJECTED)
|
||||
{
|
||||
types.insert(ltESCROW);
|
||||
}
|
||||
return types;
|
||||
};
|
||||
|
||||
@@ -1460,10 +1483,11 @@ Transactor::processPersistentChanges(TER result, XRPAmount fee)
|
||||
auto const typesToCollect = typesForResult(result);
|
||||
|
||||
std::map<LedgerEntryType, std::vector<uint256>> deletedObjects;
|
||||
std::map<LedgerEntryType, std::vector<std::pair<uint256, SLE::const_pointer>>> modifiedObjects;
|
||||
if (!typesToCollect.empty())
|
||||
{
|
||||
ctx_.visit(
|
||||
[&typesToCollect, &deletedObjects](
|
||||
[&typesToCollect, &deletedObjects, &modifiedObjects](
|
||||
uint256 const& index, bool isDelete, SLE::const_ref before, SLE::const_ref after) {
|
||||
if (isDelete)
|
||||
{
|
||||
@@ -1487,6 +1511,16 @@ Transactor::processPersistentChanges(TER result, XRPAmount fee)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (after)
|
||||
{
|
||||
// Collect modified escrows so that data written by a
|
||||
// rejected WASM execution can be re-applied after the
|
||||
// context is reset.
|
||||
auto const type = after->getType();
|
||||
if (typesToCollect.contains(type) && type == ltESCROW &&
|
||||
after->isFieldPresent(sfData))
|
||||
modifiedObjects[type].emplace_back(index, after);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1533,6 +1567,24 @@ Transactor::processPersistentChanges(TER result, XRPAmount fee)
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
for (auto const& [type, ids] : modifiedObjects)
|
||||
{
|
||||
if (ids.empty() || !typesToApply.contains(type))
|
||||
continue;
|
||||
switch (type)
|
||||
{
|
||||
case ltESCROW:
|
||||
modifyWasmDataFields(view(), ids, viewJ);
|
||||
break;
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE(
|
||||
"xrpl::Transactor::processPersistentChanges() : "
|
||||
"unexpected type");
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {result, fee, isTecClaim(result)};
|
||||
@@ -1652,7 +1704,8 @@ Transactor::operator()()
|
||||
}
|
||||
else if (
|
||||
(result == tecOVERSIZE) || (result == tecKILLED) || (result == tecINCOMPLETE) ||
|
||||
(result == tecEXPIRED) || (isTecClaimHardFail(result, view().flags())))
|
||||
(result == tecEXPIRED) || (result == tecBYTECODE_REJECTED) ||
|
||||
(isTecClaimHardFail(result, view().flags())))
|
||||
{
|
||||
std::tie(result, fee, applied) = processPersistentChanges(result, fee);
|
||||
}
|
||||
@@ -1713,6 +1766,69 @@ Transactor::operator()()
|
||||
applied = false;
|
||||
}
|
||||
|
||||
if (metadata && ctx_.getEmittedTxns().size() > 0)
|
||||
{
|
||||
OpenView emittedTxnsView(kBatchView, ctx_.openView());
|
||||
auto const parentBatchId = ctx_.tx.getTransactionID();
|
||||
|
||||
auto applyOneTransaction = [this, &parentBatchId, &emittedTxnsView](STTx const& tx) {
|
||||
OpenView perTxBatchView(kBatchView, emittedTxnsView);
|
||||
|
||||
auto const ret = xrpl::apply(
|
||||
ctx_.registry, perTxBatchView, parentBatchId, tx, TapBatch, ctx_.journal);
|
||||
XRPL_ASSERT(
|
||||
ret.applied == (isTesSuccess(ret.ter) || isTecClaim(ret.ter)),
|
||||
"Inner transaction should not be applied");
|
||||
|
||||
JLOG(ctx_.journal.debug())
|
||||
<< "BatchTrace[" << parentBatchId << "]: " << tx.getTransactionID() << " "
|
||||
<< (ret.applied ? "applied" : "failure") << ": " << transToken(ret.ter);
|
||||
|
||||
// If the transaction should be applied push its changes to the
|
||||
// whole-batch view.
|
||||
if (ret.applied && (isTesSuccess(ret.ter) || isTecClaim(ret.ter)))
|
||||
perTxBatchView.apply(emittedTxnsView);
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
bool emitResult = true;
|
||||
auto emittedTxns = ctx_.getEmittedTxns();
|
||||
while (!emittedTxns.empty())
|
||||
{
|
||||
auto txn = emittedTxns.front();
|
||||
emittedTxns.pop();
|
||||
auto const result = applyOneTransaction(*txn);
|
||||
XRPL_ASSERT(
|
||||
result.applied == (isTesSuccess(result.ter) || isTecClaim(result.ter)),
|
||||
"Outer Batch failure, inner transaction should not be applied");
|
||||
|
||||
if (!isTesSuccess(result.ter))
|
||||
emitResult = false;
|
||||
}
|
||||
|
||||
if (emitResult)
|
||||
emittedTxnsView.apply(ctx_.openView());
|
||||
else
|
||||
{
|
||||
// reset context
|
||||
result = tecBYTECODE_REJECTED;
|
||||
auto const resetResult = reset(fee);
|
||||
if (!isTesSuccess(resetResult.first))
|
||||
result = resetResult.first;
|
||||
fee = resetResult.second;
|
||||
|
||||
// InvariantCheck. The context has just been reset, so only
|
||||
// protocol invariants are meaningful here.
|
||||
result = ctx_.checkInvariants(result, fee);
|
||||
|
||||
// apply
|
||||
metadata = ctx_.apply(result);
|
||||
}
|
||||
}
|
||||
|
||||
ctx_.finalize();
|
||||
|
||||
JLOG(j_.trace()) << (applied ? "applied " : "not applied ") << transToken(result);
|
||||
|
||||
return {result, applied, metadata};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user