events.rs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::build_solidity;
  3. use ink_env::{
  4. hash::{Blake2x256, CryptoHash},
  5. topics::PrefixedValue,
  6. };
  7. use ink_primitives::{AccountId, Hash};
  8. use parity_scale_codec::Encode;
  9. use solang::{file_resolver::FileResolver, Target};
  10. use std::ffi::OsStr;
  11. fn topic_hash(encoded: &[u8]) -> Hash {
  12. let mut buf = [0; 32];
  13. if encoded.len() <= 32 {
  14. buf[..encoded.len()].copy_from_slice(encoded);
  15. } else {
  16. <Blake2x256 as CryptoHash>::hash(encoded, &mut buf);
  17. };
  18. buf.into()
  19. }
  20. #[test]
  21. fn anonymous() {
  22. let mut runtime = build_solidity(
  23. r##"
  24. contract a {
  25. event foo(bool b) anonymous;
  26. function emit_event() public {
  27. emit foo(true);
  28. }
  29. }"##,
  30. );
  31. runtime.constructor(0, Vec::new());
  32. runtime.function("emit_event", Vec::new());
  33. assert_eq!(runtime.events().len(), 1);
  34. let event = &runtime.events()[0];
  35. assert_eq!(event.topics.len(), 0);
  36. assert_eq!(event.data, (0u8, true).encode());
  37. }
  38. #[test]
  39. fn emit() {
  40. #[derive(Encode)]
  41. enum Event {
  42. Foo(bool, u32, i64),
  43. Bar(u32, u64, String),
  44. }
  45. let mut runtime = build_solidity(
  46. r##"
  47. contract a {
  48. event foo(bool,uint32,int64 indexed i);
  49. event bar(uint32,uint64,string indexed s);
  50. function emit_event() public {
  51. emit foo(true, 102, 1);
  52. emit bar(0xdeadcafe, 102, "foobar");
  53. }
  54. }"##,
  55. );
  56. runtime.constructor(0, Vec::new());
  57. runtime.function("emit_event", Vec::new());
  58. assert_eq!(runtime.events().len(), 2);
  59. let event = &runtime.events()[0];
  60. assert_eq!(event.topics.len(), 2);
  61. assert_eq!(event.topics[0], topic_hash(b"\0a::foo"));
  62. let topic = PrefixedValue {
  63. prefix: b"a::foo::i",
  64. value: &1i64,
  65. }
  66. .encode();
  67. assert_eq!(event.topics[1], topic_hash(&topic[..]));
  68. assert_eq!(event.data, Event::Foo(true, 102, 1).encode());
  69. let event = &runtime.events()[1];
  70. assert_eq!(event.topics.len(), 2);
  71. println!("topic hash: {:?}", event.topics[0]);
  72. println!("topic hash: {:?}", event.topics[0]);
  73. assert_eq!(event.topics[0], topic_hash(b"\0a::bar"));
  74. let topic = PrefixedValue {
  75. prefix: b"a::bar::s",
  76. value: &String::from("foobar"),
  77. }
  78. .encode();
  79. assert_eq!(event.topics[1], topic_hash(&topic[..]));
  80. assert_eq!(
  81. event.data,
  82. Event::Bar(0xdeadcafe, 102, "foobar".into()).encode()
  83. );
  84. }
  85. #[test]
  86. fn event_imported() {
  87. let mut cache = FileResolver::new();
  88. cache.set_file_contents(
  89. "a.sol",
  90. r#"
  91. import "b.sol";
  92. contract foo {
  93. function emit_event() public {
  94. emit bar(102, true);
  95. }
  96. }
  97. "#
  98. .to_string(),
  99. );
  100. cache.set_file_contents(
  101. "b.sol",
  102. r#"
  103. event bar (uint32 indexed f1, bool x);
  104. "#
  105. .to_string(),
  106. );
  107. let ns =
  108. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  109. assert!(!ns.diagnostics.any_errors());
  110. let mut cache = FileResolver::new();
  111. cache.set_file_contents(
  112. "a.sol",
  113. r#"
  114. import "b.sol";
  115. contract foo {
  116. function emit_event() public {
  117. emit baz.bar(102, true);
  118. }
  119. }
  120. "#
  121. .to_string(),
  122. );
  123. cache.set_file_contents(
  124. "b.sol",
  125. r#"
  126. abstract contract baz {
  127. event bar (uint32 indexed f1, bool x);
  128. }
  129. "#
  130. .to_string(),
  131. );
  132. let ns =
  133. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  134. assert!(!ns.diagnostics.any_errors());
  135. let mut cache = FileResolver::new();
  136. cache.set_file_contents(
  137. "a.sol",
  138. r#"
  139. import "b.sol" as X;
  140. contract foo {
  141. function emit_event() public {
  142. emit X.baz.bar(102, true);
  143. }
  144. }
  145. "#
  146. .to_string(),
  147. );
  148. cache.set_file_contents(
  149. "b.sol",
  150. r#"
  151. abstract contract baz {
  152. event bar (uint32 indexed f1, bool x);
  153. }
  154. "#
  155. .to_string(),
  156. );
  157. let ns =
  158. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  159. assert!(!ns.diagnostics.any_errors());
  160. let mut cache = FileResolver::new();
  161. cache.set_file_contents(
  162. "a.sol",
  163. r#"
  164. import "b.sol" as X;
  165. contract foo {
  166. function emit_event() public {
  167. emit X.bar(102, true);
  168. }
  169. }
  170. "#
  171. .to_string(),
  172. );
  173. cache.set_file_contents(
  174. "b.sol",
  175. r#"
  176. event bar (uint32 indexed f1, bool x);
  177. "#
  178. .to_string(),
  179. );
  180. let ns =
  181. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  182. assert!(!ns.diagnostics.any_errors());
  183. }
  184. /// FIXME: Use the exact same event structure once the `Option<T>` type is available
  185. #[test]
  186. fn erc20_ink_example() {
  187. #[derive(Encode)]
  188. enum Event {
  189. Transfer(AccountId, AccountId, u128),
  190. }
  191. #[derive(Encode)]
  192. struct Transfer {
  193. from: AccountId,
  194. to: AccountId,
  195. value: u128,
  196. }
  197. let mut runtime = build_solidity(
  198. r##"
  199. contract Erc20 {
  200. event Transfer(
  201. address indexed from,
  202. address indexed to,
  203. uint128 value
  204. );
  205. function emit_event(address from, address to, uint128 value) public {
  206. emit Transfer(from, to, value);
  207. }
  208. }"##,
  209. );
  210. runtime.constructor(0, Vec::new());
  211. let from = AccountId::from([1; 32]);
  212. let to = AccountId::from([2; 32]);
  213. let value = 10;
  214. runtime.function("emit_event", Transfer { from, to, value }.encode());
  215. assert_eq!(runtime.events().len(), 1);
  216. let event = &runtime.events()[0];
  217. assert_eq!(event.data, Event::Transfer(from, to, value).encode());
  218. assert_eq!(event.topics.len(), 3);
  219. assert_eq!(event.topics[0], topic_hash(b"\0Erc20::Transfer"));
  220. let expected_topic = PrefixedValue {
  221. prefix: b"Erc20::Transfer::from",
  222. value: &from,
  223. };
  224. assert_eq!(event.topics[1], topic_hash(&expected_topic.encode()));
  225. let expected_topic = PrefixedValue {
  226. prefix: b"Erc20::Transfer::to",
  227. value: &to,
  228. };
  229. assert_eq!(event.topics[2], topic_hash(&expected_topic.encode()));
  230. }
  231. #[test]
  232. fn freestanding() {
  233. let mut runtime = build_solidity(
  234. r##"
  235. event A(bool indexed b);
  236. function foo() {
  237. emit A(true);
  238. }
  239. contract a {
  240. function emit_event() public {
  241. foo();
  242. }
  243. }"##,
  244. );
  245. runtime.constructor(0, Vec::new());
  246. runtime.function("emit_event", Vec::new());
  247. assert_eq!(runtime.events().len(), 1);
  248. let event = &runtime.events()[0];
  249. assert_eq!(event.data, (0u8, true).encode());
  250. assert_eq!(event.topics[0], topic_hash(b"\0a::A"));
  251. let expected_topic = PrefixedValue {
  252. prefix: b"a::A::b",
  253. value: &true,
  254. };
  255. assert_eq!(event.topics[1], topic_hash(&expected_topic.encode()));
  256. }
  257. #[test]
  258. fn different_contract() {
  259. let mut runtime = build_solidity(
  260. r##"abstract contract A { event X(bool indexed foo); }
  261. contract B { function emit_event() public { emit A.X(true); } }"##,
  262. );
  263. runtime.constructor(0, Vec::new());
  264. runtime.function("emit_event", Vec::new());
  265. assert_eq!(runtime.events().len(), 1);
  266. let event = &runtime.events()[0];
  267. assert_eq!(event.data, (0u8, true).encode());
  268. assert_eq!(event.topics[0], topic_hash(b"\0A::X"));
  269. let expected_topic = PrefixedValue {
  270. prefix: b"A::X::foo",
  271. value: &true,
  272. };
  273. assert_eq!(event.topics[1], topic_hash(&expected_topic.encode()));
  274. }