builtin.rs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::{build_solidity, BorshToken};
  3. use base58::{FromBase58, ToBase58};
  4. use num_bigint::BigInt;
  5. #[test]
  6. fn builtins() {
  7. let mut vm = build_solidity(
  8. r#"
  9. contract timestamp {
  10. function mr_now() public returns (uint64) {
  11. return block.timestamp;
  12. }
  13. function mr_slot() public returns (uint64) {
  14. return block.slot;
  15. }
  16. function mr_blocknumber() public returns (uint64) {
  17. return block.number;
  18. }
  19. function msg_data(uint32 x) public returns (bytes) {
  20. return msg.data;
  21. }
  22. function sig() public returns (bytes8) {
  23. return msg.sig;
  24. }
  25. function prog() public returns (address) {
  26. return address(this);
  27. }
  28. }"#,
  29. );
  30. let data_account = vm.initialize_data_account();
  31. vm.function("new")
  32. .accounts(vec![("dataAccount", data_account)])
  33. .call();
  34. let clock_account = <[u8; 32]>::try_from(
  35. "SysvarC1ock11111111111111111111111111111111"
  36. .from_base58()
  37. .unwrap(),
  38. )
  39. .unwrap();
  40. let returns = vm
  41. .function("mr_now")
  42. .accounts(vec![("clock", clock_account)])
  43. .call()
  44. .unwrap();
  45. assert_eq!(
  46. returns,
  47. BorshToken::Uint {
  48. width: 64,
  49. value: BigInt::from(1620656423u64)
  50. }
  51. );
  52. let returns = vm
  53. .function("mr_slot")
  54. .accounts(vec![("clock", clock_account)])
  55. .call()
  56. .unwrap();
  57. assert_eq!(
  58. returns,
  59. BorshToken::Uint {
  60. width: 64,
  61. value: BigInt::from(70818331u64),
  62. }
  63. );
  64. let returns = vm
  65. .function("mr_blocknumber")
  66. .accounts(vec![("clock", clock_account)])
  67. .call()
  68. .unwrap();
  69. assert_eq!(
  70. returns,
  71. BorshToken::Uint {
  72. width: 64,
  73. value: BigInt::from(70818331u64)
  74. },
  75. );
  76. let returns = vm
  77. .function("msg_data")
  78. .arguments(&[BorshToken::Uint {
  79. width: 32,
  80. value: BigInt::from(0xdeadcafeu32),
  81. }])
  82. .call()
  83. .unwrap();
  84. if let BorshToken::Bytes(v) = &returns {
  85. println!("{}", hex::encode(v));
  86. }
  87. assert_eq!(
  88. returns,
  89. BorshToken::Bytes(hex::decode("a73fcaa3b216e85afecaadde").unwrap())
  90. );
  91. let returns = vm.function("sig").call().unwrap();
  92. if let Some(v) = returns.clone().into_fixed_bytes() {
  93. println!("{}", hex::encode(v));
  94. }
  95. assert_eq!(
  96. returns,
  97. BorshToken::uint8_fixed_array(hex::decode("4b22101a3c98d6cb").unwrap())
  98. );
  99. let returns = vm.function("prog").call().unwrap();
  100. assert_eq!(returns, BorshToken::Address(vm.stack[0].id));
  101. }
  102. #[test]
  103. fn pda() {
  104. let mut vm = build_solidity(
  105. r#"
  106. import 'solana';
  107. contract pda {
  108. function create_pda(bool cond) public returns (address) {
  109. address program_id = address"BPFLoaderUpgradeab1e11111111111111111111111";
  110. address addr = create_program_address(["Talking", "Cats"], program_id);
  111. if (cond) {
  112. return create_program_address(["Talking", "Squirrels"], program_id);
  113. } else {
  114. return addr;
  115. }
  116. }
  117. function create_pda2(bytes a, bytes b) public returns (address) {
  118. address program_id = address"BPFLoaderUpgradeab1e11111111111111111111111";
  119. return create_program_address([a, b], program_id);
  120. }
  121. function create_pda2_bump(bool cond) public returns (address, bytes1) {
  122. address program_id = address"BPFLoaderUpgradeab1e11111111111111111111111";
  123. (address addr, bytes1 bump) = try_find_program_address(["bar", hex"01234567"], program_id);
  124. if (cond) {
  125. return try_find_program_address(["foo", hex"01234567"], program_id);
  126. } else {
  127. return (addr, bump);
  128. }
  129. }
  130. }"#,
  131. );
  132. let data_account = vm.initialize_data_account();
  133. vm.function("new")
  134. .accounts(vec![("dataAccount", data_account)])
  135. .call();
  136. let returns = vm
  137. .function("create_pda")
  138. .arguments(&[BorshToken::Bool(true)])
  139. .accounts(vec![("systemProgram", [0; 32])])
  140. .call()
  141. .unwrap();
  142. if let Some(bs) = returns.clone().into_fixed_bytes() {
  143. assert_eq!(
  144. bs.to_base58(),
  145. "2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
  146. );
  147. } else {
  148. panic!("{returns:?} not expected");
  149. }
  150. let returns = vm
  151. .function("create_pda")
  152. .arguments(&[BorshToken::Bool(false)])
  153. .accounts(vec![("systemProgram", [0; 32])])
  154. .call()
  155. .unwrap();
  156. if let Some(bs) = returns.clone().into_fixed_bytes() {
  157. assert_eq!(
  158. bs.to_base58(),
  159. "7YgSsrAiAEJFqBNujFBRsEossqdpV31byeJLBsZ5QSJE"
  160. );
  161. } else {
  162. panic!("{returns:?} not expected");
  163. }
  164. let returns = vm
  165. .function("create_pda2")
  166. .arguments(&[
  167. BorshToken::Bytes(b"Talking".to_vec()),
  168. BorshToken::Bytes(b"Squirrels".to_vec()),
  169. ])
  170. .accounts(vec![("systemProgram", [0; 32])])
  171. .call()
  172. .unwrap();
  173. if let Some(bs) = returns.clone().into_fixed_bytes() {
  174. assert_eq!(
  175. bs.to_base58(),
  176. "2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
  177. );
  178. } else {
  179. panic!("{returns:?} not expected");
  180. }
  181. let returns = vm
  182. .function("create_pda2_bump")
  183. .arguments(&[BorshToken::Bool(true)])
  184. .call()
  185. .unwrap()
  186. .unwrap_tuple();
  187. assert_eq!(returns[1], BorshToken::uint8_fixed_array(vec![255]));
  188. if let Some(bs) = returns[0].clone().into_fixed_bytes() {
  189. assert_eq!(
  190. bs.to_base58(),
  191. "DZpR2BwsPVtbXxUUbMx5tK58Ln2T9RUtAshtR2ePqDcu"
  192. );
  193. } else {
  194. panic!("{returns:?} not expected");
  195. }
  196. let returns = vm
  197. .function("create_pda2_bump")
  198. .arguments(&[BorshToken::Bool(false)])
  199. .call()
  200. .unwrap()
  201. .unwrap_tuple();
  202. assert_eq!(returns[1], BorshToken::uint8_fixed_array(vec![255]));
  203. if let Some(bs) = returns[0].clone().into_fixed_bytes() {
  204. assert_eq!(
  205. bs.to_base58(),
  206. "3Y19WiAiLD8kT8APmtk41NgHEpkYTzx28s1uwAX8LJq4"
  207. );
  208. } else {
  209. panic!("{returns:?} not expected");
  210. }
  211. }
  212. #[test]
  213. fn test_string_bytes_buffer_write() {
  214. let mut vm = build_solidity(
  215. r#"
  216. contract Testing {
  217. function testStringAndBytes() public pure returns (bytes memory) {
  218. string str = "coffee";
  219. bytes memory b = new bytes(9);
  220. b.writeString(str, 0);
  221. bytes memory g = "tea";
  222. b.writeBytes(g, 6);
  223. return b;
  224. }
  225. }
  226. "#,
  227. );
  228. let data_account = vm.initialize_data_account();
  229. vm.function("new")
  230. .accounts(vec![("dataAccount", data_account)])
  231. .call();
  232. let returns = vm.function("testStringAndBytes").call().unwrap();
  233. let bytes = returns.into_bytes().unwrap();
  234. assert_eq!(bytes.len(), 9);
  235. assert_eq!(&bytes[0..6], b"coffee");
  236. assert_eq!(&bytes[6..9], b"tea");
  237. }
  238. #[test]
  239. #[should_panic(expected = "unexpected return 0x100000000")]
  240. fn out_of_bounds_bytes_write() {
  241. let mut vm = build_solidity(
  242. r#"
  243. contract Testing {
  244. function testBytesOut() public pure returns (bytes memory) {
  245. bytes memory b = new bytes(9);
  246. bytes memory g = "tea";
  247. b.writeBytes(g, 30);
  248. return b;
  249. }
  250. }
  251. "#,
  252. );
  253. let data_account = vm.initialize_data_account();
  254. vm.function("new")
  255. .accounts(vec![("dataAccount", data_account)])
  256. .call();
  257. let _ = vm.function("testBytesOut").call();
  258. }
  259. #[test]
  260. #[should_panic(expected = "unexpected return 0x100000000")]
  261. fn out_of_bounds_string_write() {
  262. let mut vm = build_solidity(
  263. r#"
  264. contract Testing {
  265. function testStringOut() public pure returns (bytes memory) {
  266. bytes memory b = new bytes(4);
  267. string memory str = "cappuccino";
  268. b.writeString(str, 0);
  269. return b;
  270. }
  271. }
  272. "#,
  273. );
  274. let data_account = vm.initialize_data_account();
  275. vm.function("new")
  276. .accounts(vec![("dataAccount", data_account)])
  277. .call();
  278. let _ = vm.function("testStringOut").call();
  279. }