diff --git a/src/backend/dev_helpers.rs b/src/backend/dev_helpers.rs index 0673fda1..1c6cabf7 100644 --- a/src/backend/dev_helpers.rs +++ b/src/backend/dev_helpers.rs @@ -125,6 +125,12 @@ fn stable_mem_write(input: Vec<(u64, ByteBuf)>) { if buffer.is_empty() { return; } + let mut hasher = Sha256::new(); + hasher.update(&buffer); + let result = hasher.finalize(); + use sha2::{Digest, Sha256}; + let hash = format!("{:x}", result); + ic_cdk::println!("/* {} */ \"{}\",", page, hash); let offset = page * BACKUP_PAGE_SIZE as u64; let current_size = stable::stable_size(); let needed_size = ((offset + buffer.len() as u64) >> 16) + 1; diff --git a/src/backend/updates.rs b/src/backend/updates.rs index e4d06469..65597fd4 100644 --- a/src/backend/updates.rs +++ b/src/backend/updates.rs @@ -631,6 +631,129 @@ fn backup() { }) } +#[update] +// Backup restore method. We only allow restoring the first 75 pages of stable memory and only +// once. +fn stable_mem_recovery(input: Vec<(u64, ByteBuf)>) { + // These hashes can be generated by restoring the backup from September 27, using the deployed + // replica version build from that commit. + let hashes = vec![ + /* 0 */ "f99fb568e8f5dae48279cc6c9ec0d43fac67a7521b5f1836c42a5f0038efe68c", + /* 1 */ "79574e55d3aaee2252eb869ddb627df34f7a42fadf8b5a3a7b8d5488ae45bfef", + /* 2 */ "7aa09eb068a50814b5692c5440628fad8de731d82898e0670ac2f1d49a2ea115", + /* 3 */ "e310b55b22b4e3492d7329624ff1fae1b7fce4dae51e795ac4e971ec20165d3a", + /* 4 */ "a37b2a851f8f7329777d29f5f18617a66b28c9f6693b41e3988bf047fbd13393", + /* 5 */ "ec6ef1e5eab6003f2313517101ca6a2fe0b7f1fda0cc219b78d5b3db214b8a4a", + /* 6 */ "479e71c570e2f8e7ec4e197b87613f35beeb2583d94ae692645a1fa7c99d50f9", + /* 7 */ "c972a5e711640ecf48050065b6b516c5ff294d24429d6ab68d91579c69f342ec", + /* 8 */ "786bdef851dd3aee27a19916aa78b7e0a77a11768cc240e8c28b1e4c1d32fdef", + /* 9 */ "5467a41cdf53026dc10a5c9e018281238d2e31ab02426da71bd3a0c2681add0e", + /* 10 */ "49ed985741eeb25b9c10c713048853a442d1a4736e2534d1d20e0c17fcb0cf52", + /* 11 */ "b1c9a6f5e7580696a568703c5d8b328d81fd5ff5113d00a856b40f38bcd6f0f4", + /* 12 */ "33900edff875a67ee27440d83375811f0add2b87ab215a59d5b9e0999cfd030d", + /* 13 */ "3f518e0ce027248223a3d0abbc8d696932f19bf5cf1ced3c80a7ba4f7aae3359", + /* 14 */ "17ce5dc0676b3c837e2a64f34550cf546a4d5306a659836cd00516e3cbde3b11", + /* 15 */ "10578bc3172c57ae573de5ae864a548bd0e992506277ce5270cff8936b72c545", + /* 16 */ "266ae051bb95411981b8d5009f487bd4622870ba301078e58bf879b6d2f6d57a", + /* 17 */ "09e5a36bf15d34db580e0b8b75ef1f7f1396843ff05f186ce5bfca3978a8646a", + /* 18 */ "a7b9a6bba5e4695de8438c3606ad1fb20cb6f4533c261ef870a2ef130241ff1d", + /* 19 */ "e83351e3642c27be37d2b7f2afda8775906ded16ddc764184a565662bd8e8a2c", + /* 20 */ "7cd48c52a32826b97f4162d850d559d826ceefe02f08077d8dbfe91903ef7e11", + /* 21 */ "b531223fd65ff64dee37f6f0ec2c8373cc1e08437433c9ff4f8f8e13717dbd33", + /* 22 */ "7ab6f1db6b856b2179a4bd7fba47a331bbf18dac2246a85b7681f594dd78e801", + /* 23 */ "198c66bb148c97b3868d48f661403272d40ba41b7ab44bb760286ae5c29a99f6", + /* 24 */ "344f20ffbb47bd2e844d51f7b543726bb35f31ddaea2dc940326eb1265bd1e26", + /* 25 */ "544532c223022b520f3bec22a2abc861a6979cb32a11bc43dd6992642bba5c36", + /* 26 */ "ca55a1e7bb1e1fc394dc18d6c5903c1ec419070eaa12ed37cde1fd18b9b1d0c0", + /* 27 */ "70fd9ce54e87030ed60cca33ff8dc43af72c8ed78b5cb0396609d33a0c88b3ee", + /* 28 */ "9e4dc0a368aa386355b921e9e54e9e63bf7106df42b38d83dad366c391243d3b", + /* 29 */ "dd29e17c06f53642fcf5f3ec019ae94aec8d06e1ed81becd2a76c549f3600ead", + /* 30 */ "b62d60f66cdef0d2996b30c1a04999241f8d47276b83debe55cf7d53f43492e9", + /* 31 */ "4f1bcec97f409a0f5a055da6aad19002aab9c50d6a2282af42582765463f1c9d", + /* 32 */ "d4ced8b559d28d9459205e5f0f37dc71bd279caec20f5f2f17c461a336cb10c3", + /* 33 */ "b9d998492ccf35d62588bf05d509981c6e7eebf1c0ca92a51c6168d0a108fd11", + /* 34 */ "892761a1bc6f7d058f51a5a2aeae75899774e7db0f506a0b5dcb51e97d137e8a", + /* 35 */ "fcceac9cefd37c2f1fe2c86966278f4b77edea49f259602f938356ff3f2a4082", + /* 36 */ "052982a6ccc381c169422ebef8810aa73abd9c08285afafd9dd45c1847845857", + /* 37 */ "a9e704b9850c5087736cf8d1832b6c959ea0edbb564a18dadaae8ff240bf37a0", + /* 38 */ "9863fdc6965b646f1f6cdbc3e63a13135cc6705eaca4076042b24b6443692075", + /* 39 */ "bb6946baddbca6aed16c0ced6b2fa8719e9124a3aa3b9d59225e6bcd59ac8785", + /* 40 */ "e113e814d53a1b67718d4f09fea031f2014e2abc532f27c2cfb7210861dfafef", + /* 41 */ "fb919376f88ffb2babfe2cd2c2dbe2d3de8bec63ca70166b9af26d4205f58719", + /* 42 */ "3a9f4c81073c52c8f40b7cf04ab7a15eda3240ad9255346ba47223a3d69764ac", + /* 43 */ "6ecccca09f17672f219472bbe1025922cd4ba9515220cb11c5bf69c8e6ff2d5c", + /* 44 */ "374d93fc8bec713944ac18088f24f45412c36b792dd444a1dfda4904c46723fb", + /* 45 */ "e996c44e43b7c3b73f0f41eb084d3711f0e2a3245605d073b089cef5fa811ea6", + /* 46 */ "4c7215c771378239df0318b62c86cd9a87a742a776c8042aa3cb074d47dd0bde", + /* 47 */ "cf15cd372f8405d26e3125b5eb08be6ded0456f86e5c5a939dcb58246c9b7f9d", + /* 48 */ "666b4314791227d36b75ef3c11f4faef0c84ff5e8fc2c949d1ffe8b3cc9bcb8d", + /* 49 */ "d3832d40b8c251c6f9939abc665cad0d21b2a5a064118739c9f034b0afe66949", + /* 50 */ "65dece48a9946bd343ead3ca50a7c2806b8acc12f28286e4ad21494ec1982631", + /* 51 */ "bcc40851461243c8318f9864e7800a3d42a0fed68d1d994ee9ee1a201f5a97e7", + /* 52 */ "fedc55ea57f7d06a0227c606cd1217200b632fa74e7b867fc34cdf0b699dff14", + /* 53 */ "a76c666d417fb95d5c2b7c3ce1144556bf00cc2f0e43ca875eb3854fa0934e95", + /* 54 */ "3d33f0f72d9734a6964c88d189698f0cb13db43560f1914176da083f419fcaeb", + /* 55 */ "dbfa051793b67b44a42d65a671752fe26e0ad9af161dff784dda2c8863334fb5", + /* 56 */ "c3da2254990db325f47c9307a5a7a7f38f84170e3a8ef2d9e9af5f61baeda577", + /* 57 */ "b700a7a13363e023c50bbdc4160606c8ad5132fdce97d7351570fd2433277c7d", + /* 58 */ "4d8d1a2e8cf788000d009ccd9c2be5cff4572ee226bfdc96f9dc2f12fc9cd0eb", + /* 59 */ "a26250475a7b5f83d31862fbc051c1d2c9b1e91ab861f87573641af58865a71e", + /* 60 */ "0019807968e85cca0a768ddebce962f7e903ad48bba7a9399b8df363481e904d", + /* 61 */ "a51943c1593651b21298baacb1ab1cd1521da35b094d87164b7daf8afe8dfbac", + /* 62 */ "8b291ff4670293559274539d66276fddf1715db06b356562fc3176e6c89d9613", + /* 63 */ "b6f5058d4a76559d2fa675505f51c266f92c1dde1cf5e6ebc8fd6147272dc599", + /* 64 */ "7f8f861baae4c35aca4b646892e5100367b5ee89cd5247bf3c0c97fe8471d219", + /* 65 */ "5d375f75b8a6aeaf392cefd063b6d806953b51383d38533d949a5941b811a1ad", + /* 66 */ "d833ccc7b102191d54a48194e185a62297e233957047b0be7d8ea8d7b41934ae", + /* 67 */ "12c05733c4faf4deed2e665952b4138f90340a61d31f4aa5f338c24a24be27a7", + /* 68 */ "77ca80058867c3cbea5492e3ab806a7aa3241eb4869c3167b505a0779ec69378", + /* 69 */ "445b49ddca43ce891d1b6aa5dd225b6a5ac8a110e2e93b2eb8fe5e62a32ba39a", + /* 70 */ "424fef81061698f1e5cf90a28ac91bdf3204191efe8f854030c30ca9a52b7fd1", + /* 71 */ "a85fecbb13ce8a9116118a394a77e14b3606fa70925397e6958593c14711b1ea", + /* 72 */ "bf4184d8d0709f12cb5279c564508057462b73b6a913d3f796f56332bd0a8d3b", + /* 73 */ "62e99f00eb8cd5712097c420e66d2f23e98860f244f314a075fca490db863567", + /* 74 */ "7b0e072489937ce47c83e137efc22b2c0c3713f59cd2331eb37c15db246b6981", + /* 75 */ "04555cc5ce7985651ee212a3930f232170c9f4f56277dfd3cff3a6204f22d5ea", + /* 76 */ "f15a6584b937b83134f8893d18edf23775754d130ccb15816012c30f6e6b8eac", + /* 77 */ "5782f8e0f6a8ccf4c32f02eed73bbab49a60c64aa8fca32edc7533a5a7ad9d80", + /* 78 */ "fb0b1120fb7f12351f6f7f918c1d33b78ee1875b2638dee29a2ef055352243da", + /* 79 */ "b489f78da4240cd54f150fe40fb88a8ba1ff5dd84ffbab97bd079366a5ff8e47", + ]; + use ic_cdk::api::stable; + if let Some((page, buffer)) = input.get(0) { + if page > &75 { + return; + } + let offset = page * BACKUP_PAGE_SIZE as u64; + + // Read existing page first. If it is restored already, quit. + let mut current_page = Vec::with_capacity(BACKUP_PAGE_SIZE as usize); + current_page.spare_capacity_mut(); + unsafe { + current_page.set_len(BACKUP_PAGE_SIZE as usize); + } + api::stable::stable_read(offset, &mut current_page); + if ByteBuf::from(current_page) == buffer { + ic_cdk::println!("PAGE EXISTS"); + return; + } + + use sha2::{Digest, Sha256}; + + let mut hasher = Sha256::new(); + hasher.update(&buffer); + let result = hasher.finalize(); + let hash = format!("{:x}", result); + if hash != hashes[*page as usize] { + ic_cdk::println!("WRONG HASH: {}", hash); + return; + } + + stable::stable_write(offset, buffer); + ic_cdk::println!("SUCCESS"); + } +} + #[test] fn check_candid_interface_compatibility() { use candid_parser::utils::{service_equal, CandidSource};