create_contract.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::{
  3. account_new, build_solidity, create_program_address, Account, AccountMeta, AccountState,
  4. BorshToken, Pubkey,
  5. };
  6. use base58::{FromBase58, ToBase58};
  7. #[test]
  8. fn simple_create_contract_no_seed() {
  9. let mut vm = build_solidity(
  10. r#"
  11. contract bar0 {
  12. function test_other(address foo) external returns (bar1) {
  13. bar1 x = new bar1{address: foo}("yo from bar0");
  14. return x;
  15. }
  16. function call_bar1_at_address(bar1 a, string x) public {
  17. a.say_hello(x);
  18. }
  19. }
  20. @program_id("CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT")
  21. contract bar1 {
  22. @payer(payer)
  23. constructor(string v) {
  24. print("bar1 says: " + v);
  25. }
  26. function say_hello(string v) public {
  27. print("Hello {}".format(v));
  28. }
  29. }"#,
  30. );
  31. vm.set_program(0);
  32. let data_account = vm.initialize_data_account();
  33. vm.function("new")
  34. .accounts(vec![("dataAccount", data_account)])
  35. .call();
  36. let program_id: Account = "CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT"
  37. .from_base58()
  38. .unwrap()
  39. .try_into()
  40. .unwrap();
  41. let acc = account_new();
  42. let payer = account_new();
  43. println!("new account: {}", acc.to_base58());
  44. vm.account_data.insert(payer, AccountState::default());
  45. vm.account_data.insert(
  46. acc,
  47. AccountState {
  48. data: Vec::new(),
  49. owner: Some(program_id),
  50. lamports: 0,
  51. },
  52. );
  53. let bar1 = vm
  54. .function("test_other")
  55. .arguments(&[BorshToken::Address(acc)])
  56. .accounts(vec![
  57. ("dataAccount", data_account),
  58. ("payer", payer),
  59. ("systemProgram", [0; 32]),
  60. ])
  61. .remaining_accounts(&[AccountMeta {
  62. pubkey: Pubkey(acc),
  63. is_writable: true,
  64. is_signer: true,
  65. }])
  66. .call()
  67. .unwrap();
  68. assert_eq!(vm.logs, "bar1 says: yo from bar0");
  69. assert_eq!(vm.account_data[&acc].data.len(), 16);
  70. vm.logs.truncate(0);
  71. vm.function("call_bar1_at_address")
  72. .arguments(&[bar1, BorshToken::String(String::from("xywoleh"))])
  73. .accounts(vec![
  74. ("dataAccount", data_account),
  75. ("systemProgram", [0; 32]),
  76. ])
  77. .remaining_accounts(&[
  78. AccountMeta {
  79. pubkey: Pubkey(acc),
  80. is_signer: false,
  81. is_writable: false,
  82. },
  83. AccountMeta {
  84. pubkey: Pubkey(program_id),
  85. is_writable: false,
  86. is_signer: false,
  87. },
  88. ])
  89. .call();
  90. assert_eq!(vm.logs, "Hello xywoleh");
  91. }
  92. #[test]
  93. fn simple_create_contract() {
  94. let mut vm = build_solidity(
  95. r#"
  96. contract bar0 {
  97. function test_other(address foo) external returns (bar1) {
  98. bar1 x = new bar1{address: foo}("yo from bar0");
  99. return x;
  100. }
  101. function call_bar1_at_address(bar1 a, string x) public {
  102. a.say_hello(x);
  103. }
  104. }
  105. @program_id("CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT")
  106. contract bar1 {
  107. @payer(pay)
  108. constructor(string v) {
  109. print("bar1 says: " + v);
  110. }
  111. function say_hello(string v) public {
  112. print("Hello {}".format(v));
  113. }
  114. }"#,
  115. );
  116. vm.set_program(0);
  117. let data_account = vm.initialize_data_account();
  118. vm.function("new")
  119. .accounts(vec![("dataAccount", data_account)])
  120. .call();
  121. let program_id: Account = "CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT"
  122. .from_base58()
  123. .unwrap()
  124. .try_into()
  125. .unwrap();
  126. let seed = vm.create_pda(&program_id, 7);
  127. let payer = account_new();
  128. vm.account_data.insert(payer, AccountState::default());
  129. let bar1 = vm
  130. .function("test_other")
  131. .arguments(&[BorshToken::Address(seed.0)])
  132. .accounts(vec![
  133. ("dataAccount", data_account),
  134. ("pay", payer),
  135. ("systemProgram", [0; 32]),
  136. ])
  137. .remaining_accounts(&[AccountMeta {
  138. pubkey: Pubkey(seed.0),
  139. is_signer: false,
  140. is_writable: true,
  141. }])
  142. .call()
  143. .unwrap();
  144. assert_eq!(vm.logs, "bar1 says: yo from bar0");
  145. vm.logs.truncate(0);
  146. println!("next test, {bar1:?}");
  147. vm.function("call_bar1_at_address")
  148. .arguments(&[bar1, BorshToken::String(String::from("xywoleh"))])
  149. .accounts(vec![
  150. ("dataAccount", data_account),
  151. ("systemProgram", [0; 32]),
  152. ])
  153. .remaining_accounts(&[
  154. AccountMeta {
  155. pubkey: Pubkey(seed.0),
  156. is_signer: false,
  157. is_writable: false,
  158. },
  159. AccountMeta {
  160. pubkey: Pubkey(program_id),
  161. is_writable: false,
  162. is_signer: false,
  163. },
  164. ])
  165. .call();
  166. assert_eq!(vm.logs, "Hello xywoleh");
  167. }
  168. #[test]
  169. fn create_contract_wrong_program_id() {
  170. let mut vm = build_solidity(
  171. r#"
  172. @program_id("CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT")
  173. contract bar0 {}
  174. "#,
  175. );
  176. let data_account = vm.initialize_data_account();
  177. vm.function("new")
  178. .accounts(vec![("dataAccount", data_account)])
  179. .call();
  180. let program = &vm.programs[0].id;
  181. let code = vm.account_data[program].data.clone();
  182. let mut vm = build_solidity(
  183. r#"
  184. @program_id("25UGQeMKp1YH8dR1WBtaj26iqfc49xjwfvLnUKavcz8E")
  185. contract bar0 {}
  186. "#,
  187. );
  188. let program = &vm.programs[0].id;
  189. vm.account_data.get_mut(program).unwrap().data = code;
  190. let data_account = vm.initialize_data_account();
  191. vm.function("new")
  192. .accounts(vec![("dataAccount", data_account)])
  193. .expected(7 << 32)
  194. .call();
  195. assert_eq!(
  196. vm.logs,
  197. "program_id should be CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT"
  198. );
  199. }
  200. #[test]
  201. fn call_constructor_twice() {
  202. let mut vm = build_solidity(
  203. r#"
  204. @program_id("CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT")
  205. contract bar0 {}
  206. "#,
  207. );
  208. let data_account = vm.initialize_data_account();
  209. vm.function("new")
  210. .accounts(vec![("dataAccount", data_account)])
  211. .call();
  212. vm.function("new")
  213. .accounts(vec![("dataAccount", data_account)])
  214. .expected(2)
  215. .call();
  216. }
  217. #[test]
  218. fn create_contract_with_payer() {
  219. let mut vm = build_solidity(
  220. r#"
  221. contract x {
  222. uint64 v;
  223. @payer(p)
  224. constructor() {
  225. v = 102;
  226. }
  227. function f() public returns (uint64) {
  228. return v;
  229. }
  230. }"#,
  231. );
  232. let payer = account_new();
  233. vm.account_data.insert(payer, AccountState::default());
  234. let data_account = vm.initialize_data_account();
  235. vm.function("new")
  236. .accounts(vec![
  237. ("dataAccount", data_account),
  238. ("p", payer),
  239. ("systemProgram", [0; 32]),
  240. ])
  241. .call();
  242. let ret = vm
  243. .function("f")
  244. .accounts(vec![("dataAccount", data_account)])
  245. .call()
  246. .unwrap();
  247. assert_eq!(
  248. ret,
  249. BorshToken::Uint {
  250. width: 64,
  251. value: 102.into()
  252. }
  253. );
  254. }
  255. #[test]
  256. #[should_panic(expected = "external call failed")]
  257. // 64424509440 = 15 << 32 (ERROR_NEW_ACCOUNT_NEEDED)
  258. fn missing_contract() {
  259. let mut vm = build_solidity(
  260. r#"
  261. contract bar0 {
  262. function test_other(address foo) external returns (bar1) {
  263. bar1 x = new bar1{address: foo}("yo from bar0");
  264. return x;
  265. }
  266. function call_bar1_at_address(bar1 a, string x) public {
  267. a.say_hello(x);
  268. }
  269. }
  270. @program_id("7vJKRaKLGCNUPuHWdeHCTknkYf3dHXXEZ6ri7dc6ngeV")
  271. contract bar1 {
  272. constructor(string v) {
  273. print("bar1 says: " + v);
  274. }
  275. function say_hello(string v) public {
  276. print("Hello {}".format(v));
  277. }
  278. }"#,
  279. );
  280. vm.set_program(0);
  281. let data_account = vm.initialize_data_account();
  282. vm.function("new")
  283. .accounts(vec![("dataAccount", data_account)])
  284. .call();
  285. let missing = account_new();
  286. vm.logs.clear();
  287. vm.account_data.insert(missing, AccountState::default());
  288. let program_id: Account = "7vJKRaKLGCNUPuHWdeHCTknkYf3dHXXEZ6ri7dc6ngeV"
  289. .from_base58()
  290. .unwrap()
  291. .try_into()
  292. .unwrap();
  293. // There is no payer account, so the external call fails.
  294. let _ = vm
  295. .function("test_other")
  296. .arguments(&[BorshToken::Address(missing)])
  297. .accounts(vec![
  298. ("dataAccount", data_account),
  299. ("systemProgram", [0; 32]),
  300. ])
  301. .remaining_accounts(&[
  302. AccountMeta {
  303. pubkey: Pubkey(missing),
  304. is_signer: true,
  305. is_writable: false,
  306. },
  307. AccountMeta {
  308. pubkey: Pubkey(program_id),
  309. is_writable: false,
  310. is_signer: false,
  311. },
  312. ])
  313. .must_fail();
  314. }
  315. #[test]
  316. fn two_contracts() {
  317. let mut vm = build_solidity(
  318. r#"
  319. contract bar0 {
  320. function test_other(address a, address b) external returns (bar1) {
  321. bar1 x = new bar1{address: a}("yo from bar0");
  322. bar1 y = new bar1{address: b}("hi from bar0");
  323. return x;
  324. }
  325. }
  326. @program_id("CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT")
  327. contract bar1 {
  328. @payer(payer_account)
  329. constructor(string v) {
  330. print("bar1 says: " + v);
  331. }
  332. }"#,
  333. );
  334. vm.set_program(0);
  335. let data_account = vm.initialize_data_account();
  336. vm.function("new")
  337. .accounts(vec![("dataAccount", data_account)])
  338. .call();
  339. let program_id: Account = "CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT"
  340. .from_base58()
  341. .unwrap()
  342. .try_into()
  343. .unwrap();
  344. let seed1 = vm.create_pda(&program_id, 5);
  345. let seed2 = vm.create_pda(&program_id, 5);
  346. let payer = account_new();
  347. vm.account_data.insert(seed1.0, AccountState::default());
  348. vm.account_data.insert(seed2.0, AccountState::default());
  349. vm.account_data.insert(payer, AccountState::default());
  350. let _bar1 = vm
  351. .function("test_other")
  352. .arguments(&[BorshToken::Address(seed1.0), BorshToken::Address(seed2.0)])
  353. .accounts(vec![
  354. ("dataAccount", data_account),
  355. ("systemProgram", [0; 32]),
  356. ("payer_account", payer),
  357. ])
  358. .remaining_accounts(&[
  359. AccountMeta {
  360. pubkey: Pubkey(seed1.0),
  361. is_signer: true,
  362. is_writable: true,
  363. },
  364. AccountMeta {
  365. pubkey: Pubkey(seed2.0),
  366. is_signer: true,
  367. is_writable: true,
  368. },
  369. AccountMeta {
  370. pubkey: Pubkey(program_id),
  371. is_writable: false,
  372. is_signer: false,
  373. },
  374. ])
  375. .call();
  376. assert_eq!(vm.logs, "bar1 says: yo from bar0bar1 says: hi from bar0");
  377. vm.logs.truncate(0);
  378. }
  379. #[test]
  380. fn account_too_small() {
  381. let mut vm = build_solidity(
  382. r#"
  383. contract bar {
  384. int[200] foo1;
  385. }"#,
  386. );
  387. let data_account = vm.initialize_data_account();
  388. vm.account_data
  389. .get_mut(&data_account)
  390. .unwrap()
  391. .data
  392. .truncate(100);
  393. vm.function("new")
  394. .accounts(vec![("dataAccount", data_account)])
  395. .expected(5 << 32)
  396. .call();
  397. }
  398. #[test]
  399. fn account_with_space() {
  400. let mut vm = build_solidity(
  401. r#"
  402. contract bar {
  403. @payer(payer)
  404. constructor(@space uint64 x) {}
  405. function hello() public returns (bool) {
  406. return true;
  407. }
  408. }
  409. "#,
  410. );
  411. let data_account = vm.initialize_data_account();
  412. vm.account_data
  413. .get_mut(&data_account)
  414. .unwrap()
  415. .data
  416. .truncate(0);
  417. let payer = account_new();
  418. vm.account_data.insert(payer, AccountState::default());
  419. vm.function("new")
  420. .accounts(vec![
  421. ("dataAccount", data_account),
  422. ("payer", payer),
  423. ("systemProgram", [0; 32]),
  424. ])
  425. .arguments(&[BorshToken::Uint {
  426. width: 64,
  427. value: 306.into(),
  428. }])
  429. .call();
  430. assert_eq!(
  431. vm.account_data.get_mut(&data_account).unwrap().data.len(),
  432. 306
  433. );
  434. let ret = vm
  435. .function("hello")
  436. .accounts(vec![("dataAccount", data_account)])
  437. .call()
  438. .unwrap();
  439. assert_eq!(ret, BorshToken::Bool(true));
  440. }
  441. #[test]
  442. fn account_with_seed() {
  443. let mut vm = build_solidity(
  444. r#"
  445. contract bar {
  446. @space(511 + 102)
  447. @payer(payer)
  448. constructor(@seed bytes seed) {}
  449. function hello() public returns (bool) {
  450. return true;
  451. }
  452. }
  453. "#,
  454. );
  455. let program_id = vm.stack[0].id;
  456. let seed = vm.create_pda(&program_id, 7);
  457. let payer = account_new();
  458. vm.account_data.insert(payer, AccountState::default());
  459. vm.function("new")
  460. .accounts(vec![
  461. ("dataAccount", seed.0),
  462. ("payer", payer),
  463. ("systemProgram", [0; 32]),
  464. ])
  465. .arguments(&[BorshToken::Bytes(seed.1)])
  466. .call();
  467. assert_eq!(
  468. vm.account_data.get_mut(&seed.0).unwrap().data.len(),
  469. 511 + 102
  470. );
  471. let ret = vm
  472. .function("hello")
  473. .accounts(vec![("dataAccount", seed.0)])
  474. .call()
  475. .unwrap();
  476. assert_eq!(ret, BorshToken::Bool(true));
  477. }
  478. #[test]
  479. fn account_with_seed_bump() {
  480. let mut vm = build_solidity(
  481. r#"
  482. contract bar {
  483. @space(511 + 102)
  484. @payer(payer)
  485. constructor(@seed address seed, @seed bytes2 seed2, @bump byte b) {}
  486. function hello() public returns (bool) {
  487. return true;
  488. }
  489. }
  490. "#,
  491. );
  492. let program_id = vm.stack[0].id;
  493. let (address, full_seed) = vm.create_pda(&program_id, 35);
  494. let bump = full_seed[34];
  495. let seed_addr = &full_seed[0..32];
  496. let seed2 = &full_seed[32..34];
  497. let payer = account_new();
  498. vm.account_data.insert(payer, AccountState::default());
  499. vm.function("new")
  500. .arguments(&[
  501. BorshToken::Address(seed_addr.try_into().unwrap()),
  502. BorshToken::FixedBytes(seed2.to_vec()),
  503. BorshToken::Uint {
  504. width: 8,
  505. value: bump.into(),
  506. },
  507. ])
  508. .accounts(vec![
  509. ("dataAccount", address),
  510. ("payer", payer),
  511. ("systemProgram", [0; 32]),
  512. ])
  513. .call();
  514. assert_eq!(
  515. vm.account_data.get_mut(&address).unwrap().data.len(),
  516. 511 + 102
  517. );
  518. let ret = vm
  519. .function("hello")
  520. .accounts(vec![("dataAccount", address)])
  521. .call()
  522. .unwrap();
  523. assert_eq!(ret, BorshToken::Bool(true));
  524. }
  525. #[test]
  526. fn account_with_seed_bump_literals() {
  527. let mut vm = build_solidity(
  528. r#"
  529. @program_id("vS5Tf8mnHGbUCMLQWrnvsFvwHLfA5p3yQM3ozxPckn8")
  530. contract bar {
  531. @space(2 << 8 + 4)
  532. @seed("meh")
  533. @bump(33) // 33 = ascii !
  534. @payer(my_account)
  535. constructor() {}
  536. function hello() public returns (bool) {
  537. return true;
  538. }
  539. }
  540. "#,
  541. );
  542. let program_id = vm.stack[0].id;
  543. let account = create_program_address(&program_id, &[b"meh!"]);
  544. let payer = account_new();
  545. vm.create_empty_account(&account.0, &program_id);
  546. vm.account_data.insert(payer, AccountState::default());
  547. vm.function("new")
  548. .accounts(vec![
  549. ("dataAccount", account.0),
  550. ("my_account", payer),
  551. ("systemProgram", [0; 32]),
  552. ])
  553. .call();
  554. assert_eq!(
  555. vm.account_data.get_mut(&account.0).unwrap().data.len(),
  556. 8192
  557. );
  558. let ret = vm
  559. .function("hello")
  560. .accounts(vec![("dataAccount", account.0)])
  561. .call()
  562. .unwrap();
  563. assert_eq!(ret, BorshToken::Bool(true));
  564. }
  565. #[test]
  566. fn create_child() {
  567. let mut vm = build_solidity(
  568. r#"
  569. contract creator {
  570. Child public c;
  571. function create_child(address child) external {
  572. print("Going to create child");
  573. c = new Child{address: child}();
  574. c.say_hello();
  575. }
  576. }
  577. @program_id("Chi1d5XD6nTAp2EyaNGqMxZzUjh6NvhXRxbGHP3D1RaT")
  578. contract Child {
  579. @payer(payer)
  580. @space(511 + 7)
  581. constructor() {
  582. print("In child constructor");
  583. }
  584. function say_hello() pure public {
  585. print("Hello there");
  586. }
  587. }"#,
  588. );
  589. vm.set_program(0);
  590. let data_account = vm.initialize_data_account();
  591. vm.function("new")
  592. .accounts(vec![("dataAccount", data_account)])
  593. .call();
  594. let payer = account_new();
  595. let program_id = vm.stack[0].id;
  596. let seed = vm.create_pda(&program_id, 7);
  597. vm.account_data.insert(payer, AccountState::default());
  598. vm.account_data.insert(seed.0, AccountState::default());
  599. vm.function("create_child")
  600. .arguments(&[BorshToken::Address(seed.0)])
  601. .accounts(vec![
  602. ("dataAccount", data_account),
  603. ("payer", payer),
  604. ("systemProgram", [0; 32]),
  605. ])
  606. .remaining_accounts(&[AccountMeta {
  607. pubkey: Pubkey(seed.0),
  608. is_signer: true,
  609. is_writable: true,
  610. }])
  611. .call();
  612. assert_eq!(
  613. vm.logs,
  614. "Going to create childIn child constructorHello there"
  615. );
  616. }
  617. #[test]
  618. fn create_child_with_meta() {
  619. let mut vm = build_solidity(
  620. r#"
  621. import 'solana';
  622. contract creator {
  623. Child public c;
  624. function create_child_with_meta(address child, address payer) public {
  625. print("Going to create child");
  626. AccountMeta[2] metas = [
  627. AccountMeta({pubkey: child, is_signer: true, is_writable: true}),
  628. AccountMeta({pubkey: payer, is_signer: true, is_writable: true})
  629. // Passing the system account here crashes the VM, even if I add it to vm.account_data
  630. // AccountMeta({pubkey: address"11111111111111111111111111111111", is_writable: false, is_signer: false})
  631. ];
  632. c = new Child{accounts: metas}();
  633. c.say_hello();
  634. }
  635. }
  636. @program_id("Chi1d5XD6nTAp2EyaNGqMxZzUjh6NvhXRxbGHP3D1RaT")
  637. contract Child {
  638. @payer(payer)
  639. @space(511 + 7)
  640. constructor() {
  641. print("In child constructor");
  642. }
  643. function say_hello() pure public {
  644. print("Hello there");
  645. }
  646. }
  647. "#,
  648. );
  649. vm.set_program(0);
  650. let data_account = vm.initialize_data_account();
  651. vm.function("new")
  652. .accounts(vec![("dataAccount", data_account)])
  653. .call();
  654. let payer = account_new();
  655. let program_id = vm.stack[0].id;
  656. let seed = vm.create_pda(&program_id, 7);
  657. vm.account_data.insert(seed.0, AccountState::default());
  658. vm.account_data.insert(payer, AccountState::default());
  659. vm.function("create_child_with_meta")
  660. .arguments(&[BorshToken::Address(seed.0), BorshToken::Address(payer)])
  661. .accounts(vec![
  662. ("dataAccount", data_account),
  663. ("systemProgram", [0; 32]),
  664. ])
  665. .remaining_accounts(&[
  666. AccountMeta {
  667. pubkey: Pubkey(seed.0),
  668. is_signer: false,
  669. is_writable: false,
  670. },
  671. AccountMeta {
  672. pubkey: Pubkey(payer),
  673. is_signer: true,
  674. is_writable: false,
  675. },
  676. ])
  677. .call();
  678. assert_eq!(
  679. vm.logs,
  680. "Going to create childIn child constructorHello there"
  681. );
  682. }