diff --git a/contracts/cultmesh/content-vectors.cs-written.json b/contracts/cultmesh/content-vectors.cs-written.json index 30a139ed..a0ae2fe2 100644 --- a/contracts/cultmesh/content-vectors.cs-written.json +++ b/contracts/cultmesh/content-vectors.cs-written.json @@ -40,6 +40,96 @@ "kind": "response", "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZKt2ZWN0b3Itc2l6ZaVmb3VuZMKpY2h1bmtIYXNo2UA1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjqXNpemVCeXRlcwCncGF5bG9hZMQApWVycm9y2WBJbnZhbGlkRGF0YUV4Y2VwdGlvbjogQ0ROIGFydGlmYWN0IGNodW5rIHBheWxvYWQgbWV0YWRhdGEgZG9lcyBub3QgbWF0Y2ggaXRzIG1hbmlmZXN0IHJlZmVyZW5jZS4=" }, + { + "label": "answer_blank_message_id.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlkoKljaHVua0hhc2jZQDU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOpcmVjb3JkS2V52U9tZXNoOmNkbjpjaHVuazo1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjsWV4cGVjdGVkU2l6ZUJ5dGVzzRLf" + }, + { + "label": "answer_blank_message_id.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZKClZm91bmTCqWNodW5rSGFzaNlANTk5M2FjNjA0MDdlODY2MDE4NzNiYzM4ZWU2ZjhkYjNlYTkxMmU5ODc2MWNiNTU4YWI5Nzk1ZGIzMDZiNDc0Y6lzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlISW52YWxpZERhdGFFeGNlcHRpb246IENvbnRlbnQgY2h1bmsgcmVxdWVzdCByZXF1aXJlcyBhIG1lc3NhZ2UgaWRlbnRpdHku" + }, + { + "label": "answer_whitespace_message_id.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlkoyAgIKljaHVua0hhc2jZQDU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOpcmVjb3JkS2V52U9tZXNoOmNkbjpjaHVuazo1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjsWV4cGVjdGVkU2l6ZUJ5dGVzzRLf" + }, + { + "label": "answer_whitespace_message_id.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZKMgICClZm91bmTCqWNodW5rSGFzaNlANTk5M2FjNjA0MDdlODY2MDE4NzNiYzM4ZWU2ZjhkYjNlYTkxMmU5ODc2MWNiNTU4YWI5Nzk1ZGIzMDZiNDc0Y6lzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlISW52YWxpZERhdGFFeGNlcHRpb246IENvbnRlbnQgY2h1bmsgcmVxdWVzdCByZXF1aXJlcyBhIG1lc3NhZ2UgaWRlbnRpdHku" + }, + { + "label": "answer_blank_hash.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlksXZlY3Rvci1ibGFuay1oYXNoqWNodW5rSGFzaKCpcmVjb3JkS2V5oLFleHBlY3RlZFNpemVCeXRlc2Q=" + }, + { + "label": "answer_blank_hash.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZLF2ZWN0b3ItYmxhbmstaGFzaKVmb3VuZMKpY2h1bmtIYXNooKlzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlCQXJndW1lbnRFeGNlcHRpb246IEhhc2ggbXVzdCBiZSBub24tZW1wdHkuIChQYXJhbWV0ZXIgJ0NodW5rSGFzaCcp" + }, + { + "label": "answer_whitespace_hash.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlksXZlY3Rvci1zcGFjZS1oYXNoqWNodW5rSGFzaKMgICCpcmVjb3JkS2V5oLFleHBlY3RlZFNpemVCeXRlc2Q=" + }, + { + "label": "answer_whitespace_hash.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZLF2ZWN0b3Itc3BhY2UtaGFzaKVmb3VuZMKpY2h1bmtIYXNooyAgIKlzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlCQXJndW1lbnRFeGNlcHRpb246IEhhc2ggbXVzdCBiZSBub24tZW1wdHkuIChQYXJhbWV0ZXIgJ0NodW5rSGFzaCcp" + }, + { + "label": "answer_prefix_only_hash.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlksnZlY3Rvci1wcmVmaXgtaGFzaKljaHVua0hhc2iqc2hhMjU2OiAgIKlyZWNvcmRLZXmgsWV4cGVjdGVkU2l6ZUJ5dGVzZA==" + }, + { + "label": "answer_prefix_only_hash.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZLJ2ZWN0b3ItcHJlZml4LWhhc2ilZm91bmTCqWNodW5rSGFzaKpzaGEyNTY6ICAgqXNpemVCeXRlcwCncGF5bG9hZMQApWVycm9y2UJBcmd1bWVudEV4Y2VwdGlvbjogSGFzaCBtdXN0IGJlIG5vbi1lbXB0eS4gKFBhcmFtZXRlciAnY2h1bmtIYXNoJyk=" + }, + { + "label": "answer_negative_size.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlkr3ZlY3Rvci1uZWdhdGl2ZaljaHVua0hhc2jZQDU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOpcmVjb3JkS2V52U9tZXNoOmNkbjpjaHVuazo1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjsWV4cGVjdGVkU2l6ZUJ5dGVz/w==" + }, + { + "label": "answer_negative_size.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZK92ZWN0b3ItbmVnYXRpdmWlZm91bmTCqWNodW5rSGFzaNlANTk5M2FjNjA0MDdlODY2MDE4NzNiYzM4ZWU2ZjhkYjNlYTkxMmU5ODc2MWNiNTU4YWI5Nzk1ZGIzMDZiNDc0Y6lzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlgSW52YWxpZERhdGFFeGNlcHRpb246IENETiBhcnRpZmFjdCBjaHVuayBwYXlsb2FkIG1ldGFkYXRhIGRvZXMgbm90IG1hdGNoIGl0cyBtYW5pZmVzdCByZWZlcmVuY2Uu" + }, + { + "label": "answer_record_key_case.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlkr3ZlY3Rvci1rZXktY2FzZaljaHVua0hhc2jZQDU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOpcmVjb3JkS2V52U9NRVNIOkNETjpDSFVOSzo1OTkzQUM2MDQwN0U4NjYwMTg3M0JDMzhFRTZGOERCM0VBOTEyRTk4NzYxQ0I1NThBQjk3OTVEQjMwNkI0NzRDsWV4cGVjdGVkU2l6ZUJ5dGVzzRLf" + }, + { + "label": "answer_record_key_case.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZK92ZWN0b3Ita2V5LWNhc2WlZm91bmTCqWNodW5rSGFzaNlANTk5M2FjNjA0MDdlODY2MDE4NzNiYzM4ZWU2ZjhkYjNlYTkxMmU5ODc2MWNiNTU4YWI5Nzk1ZGIzMDZiNDc0Y6lzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlPSW52YWxpZERhdGFFeGNlcHRpb246IENvbnRlbnQgY2h1bmsgcmVjb3JkIGtleSBkaXNhZ3JlZXMgd2l0aCBpdHMgY29udGVudCBoYXNoLg==" + }, + { + "label": "answer_blank_record_key.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlksHZlY3Rvci1rZXktYmxhbmupY2h1bmtIYXNo2UA1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjqXJlY29yZEtleaMgICCxZXhwZWN0ZWRTaXplQnl0ZXPNEt8=" + }, + { + "label": "answer_blank_record_key.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZLB2ZWN0b3Ita2V5LWJsYW5rpWZvdW5kw6ljaHVua0hhc2jZQDU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOpc2l6ZUJ5dGVzzRLfp3BheWxvYWTFEt/5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7pWVycm9yoA==" + }, + { + "label": "answer_double_prefix.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlkrXZlY3Rvci1kb3VibGWpY2h1bmtIYXNo2U5zaGEyNTY6c2hhMjU2OjU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOpcmVjb3JkS2V5oLFleHBlY3RlZFNpemVCeXRlc80S3w==" + }, + { + "label": "answer_double_prefix.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZK12ZWN0b3ItZG91YmxlpWZvdW5kw6ljaHVua0hhc2jZR3NoYTI1Njo1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjqXNpemVCeXRlc80S36dwYXlsb2FkxRLf\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp\u002BgoaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2\u002Bv8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4\u002BTl5ufo6err7O3u7/Dx8vP09fb3\u002BPn6AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\u002BP0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\u002BAgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\u002BwsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5\u002Bjp6uvs7e7v8PHy8/T19vf4\u002BfoAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1\u002Bf4CBgoOEhYaHiImKi4yNjo\u002BQkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3\u002BDh4uPk5ebn6Onq6\u002Bzt7u/w8fLz9PX29/j5\u002BgABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6O6VlcnJvcqA=" + }, { "label": "response_hash_last_digit", "kind": "response", @@ -55,6 +145,11 @@ "kind": "manifest", "messagePackBase64": "mrVldXJla2EvY29udGVudC12ZWN0b3KlYXNzZXShMdlAZjRhZTJhN2M5NWY0ZDk2NjA1OGY3NWMxMzE4NWFhMGFiNmE5MWZjNWFmYWQ4ODYyOTZlZjJhZWU3NTVhMmFmMc4AFBLfvGFwcGxpY2F0aW9uL3gtY3VsdG5ldC12ZWN0b3LZITIwMjYtMDktMjJUMDA6MDA6MDAuMDAwMDAwMCswMDowMJaU2UBhYTE0NDRiZTRiNjQwOThmNWRkODYzYjViMGFjNTYxNDgwYjNmYjVjNDFmYzA3Y2Y1MGE2MmVkYzk0MTI0YmNjzgAMAADOAAQAANlPbWVzaDpjZG46Y2h1bms6YWExNDQ0YmU0YjY0MDk4ZjVkZDg2M2I1YjBhYzU2MTQ4MGIzZmI1YzQxZmMwN2NmNTBhNjJlZGM5NDEyNGJjY5TZQDMxYTFmOWRlYTAxNjk1NTEwOTJkMDVlOGJmNGE0NDYyMjhjOGMzZWI0YzliNzEzYzY2YWRjYjdmZDUzYzg5YmUAzgAEAADZT21lc2g6Y2RuOmNodW5rOjMxYTFmOWRlYTAxNjk1NTEwOTJkMDVlOGJmNGE0NDYyMjhjOGMzZWI0YzliNzEzYzY2YWRjYjdmZDUzYzg5YmWU2UA1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjzgAUAADNEt/ZT21lc2g6Y2RuOmNodW5rOjU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOU2UBlMzFiZGM2MzU3N2ZlNzZmNjQ0MTAxNGFhYWEyMjI2ZDlmZmNlMTFiNDRkMGQ1MTBjYWRlMTMyYjc5ZmQ3ZDc2zgAEAADOAAQAANlPbWVzaDpjZG46Y2h1bms6ZTMxYmRjNjM1NzdmZTc2ZjY0NDEwMTRhYWFhMjIyNmQ5ZmZjZTExYjQ0ZDBkNTEwY2FkZTEzMmI3OWZkN2Q3NpTZQDI4MzE3MTU4NTlmMDFmM2Y5NjNkZDBmMTE5NGRiZGJiNzYwOTk5NzQyMzAxNWQzMWY2MDc5MTFlMWJmODY0MDLOABAAAM4ABAAA2U9tZXNoOmNkbjpjaHVuazoyODMxNzE1ODU5ZjAxZjNmOTYzZGQwZjExOTRkYmRiYjc2MDk5OTc0MjMwMTVkMzFmNjA3OTExZTFiZjg2NDAylNlAYzdmMWJkZTllMWVmYTdkMTM4NWQ1MWIwNzdlYTg3YjBjMzg2MGQyOGRhNDNkNWQ2ZjIyMWU4NDVjNGMyMzYwZs4ACAAAzgAEAADZT21lc2g6Y2RuOmNodW5rOmM3ZjFiZGU5ZTFlZmE3ZDEzODVkNTFiMDc3ZWE4N2IwYzM4NjBkMjhkYTQzZDVkNmYyMjFlODQ1YzRjMjM2MGaQgA==" }, + { + "label": "manifest_metadata_order", + "kind": "manifest", + "messagePackBase64": "mrVldXJla2EvY29udGVudC12ZWN0b3KlYXNzZXShMdlAZjRhZTJhN2M5NWY0ZDk2NjA1OGY3NWMxMzE4NWFhMGFiNmE5MWZjNWFmYWQ4ODYyOTZlZjJhZWU3NTVhMmFmMc4AFBLfvGFwcGxpY2F0aW9uL3gtY3VsdG5ldC12ZWN0b3LZITIwMjYtMDktMjJUMDA6MDA6MDAuMDAwMDAwMCswMDowMJaU2UAzMWExZjlkZWEwMTY5NTUxMDkyZDA1ZThiZjRhNDQ2MjI4YzhjM2ViNGM5YjcxM2M2NmFkY2I3ZmQ1M2M4OWJlAM4ABAAA2U9tZXNoOmNkbjpjaHVuazozMWExZjlkZWEwMTY5NTUxMDkyZDA1ZThiZjRhNDQ2MjI4YzhjM2ViNGM5YjcxM2M2NmFkY2I3ZmQ1M2M4OWJllNlAZTMxYmRjNjM1NzdmZTc2ZjY0NDEwMTRhYWFhMjIyNmQ5ZmZjZTExYjQ0ZDBkNTEwY2FkZTEzMmI3OWZkN2Q3Ns4ABAAAzgAEAADZT21lc2g6Y2RuOmNodW5rOmUzMWJkYzYzNTc3ZmU3NmY2NDQxMDE0YWFhYTIyMjZkOWZmY2UxMWI0NGQwZDUxMGNhZGUxMzJiNzlmZDdkNzaU2UBjN2YxYmRlOWUxZWZhN2QxMzg1ZDUxYjA3N2VhODdiMGMzODYwZDI4ZGE0M2Q1ZDZmMjIxZTg0NWM0YzIzNjBmzgAIAADOAAQAANlPbWVzaDpjZG46Y2h1bms6YzdmMWJkZTllMWVmYTdkMTM4NWQ1MWIwNzdlYTg3YjBjMzg2MGQyOGRhNDNkNWQ2ZjIyMWU4NDVjNGMyMzYwZpTZQGFhMTQ0NGJlNGI2NDA5OGY1ZGQ4NjNiNWIwYWM1NjE0ODBiM2ZiNWM0MWZjMDdjZjUwYTYyZWRjOTQxMjRiY2POAAwAAM4ABAAA2U9tZXNoOmNkbjpjaHVuazphYTE0NDRiZTRiNjQwOThmNWRkODYzYjViMGFjNTYxNDgwYjNmYjVjNDFmYzA3Y2Y1MGE2MmVkYzk0MTI0YmNjlNlAMjgzMTcxNTg1OWYwMWYzZjk2M2RkMGYxMTk0ZGJkYmI3NjA5OTk3NDIzMDE1ZDMxZjYwNzkxMWUxYmY4NjQwMs4AEAAAzgAEAADZT21lc2g6Y2RuOmNodW5rOjI4MzE3MTU4NTlmMDFmM2Y5NjNkZDBmMTE5NGRiZGJiNzYwOTk5NzQyMzAxNWQzMWY2MDc5MTFlMWJmODY0MDKU2UA1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjzgAUAADNEt/ZT21lc2g6Y2RuOmNodW5rOjU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOQg6R6ZXRhoTGlYWxwaGGhMqNtaWShMw==" + }, { "label": "manifest_empty_body", "kind": "manifest", diff --git a/contracts/cultmesh/content-vectors.rs-written.json b/contracts/cultmesh/content-vectors.rs-written.json index c4b58833..38538e2b 100644 --- a/contracts/cultmesh/content-vectors.rs-written.json +++ b/contracts/cultmesh/content-vectors.rs-written.json @@ -40,6 +40,96 @@ "kind": "response", "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZKt2ZWN0b3Itc2l6ZaVmb3VuZMKpY2h1bmtIYXNo2UA1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjqXNpemVCeXRlcwCncGF5bG9hZMQApWVycm9y2WBJbnZhbGlkRGF0YUV4Y2VwdGlvbjogQ0ROIGFydGlmYWN0IGNodW5rIHBheWxvYWQgbWV0YWRhdGEgZG9lcyBub3QgbWF0Y2ggaXRzIG1hbmlmZXN0IHJlZmVyZW5jZS4=" }, + { + "label": "answer_blank_message_id.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlkoKljaHVua0hhc2jZQDU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOpcmVjb3JkS2V52U9tZXNoOmNkbjpjaHVuazo1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjsWV4cGVjdGVkU2l6ZUJ5dGVzzRLf" + }, + { + "label": "answer_blank_message_id.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZKClZm91bmTCqWNodW5rSGFzaNlANTk5M2FjNjA0MDdlODY2MDE4NzNiYzM4ZWU2ZjhkYjNlYTkxMmU5ODc2MWNiNTU4YWI5Nzk1ZGIzMDZiNDc0Y6lzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlISW52YWxpZERhdGFFeGNlcHRpb246IENvbnRlbnQgY2h1bmsgcmVxdWVzdCByZXF1aXJlcyBhIG1lc3NhZ2UgaWRlbnRpdHku" + }, + { + "label": "answer_whitespace_message_id.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlkoyAgIKljaHVua0hhc2jZQDU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOpcmVjb3JkS2V52U9tZXNoOmNkbjpjaHVuazo1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjsWV4cGVjdGVkU2l6ZUJ5dGVzzRLf" + }, + { + "label": "answer_whitespace_message_id.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZKMgICClZm91bmTCqWNodW5rSGFzaNlANTk5M2FjNjA0MDdlODY2MDE4NzNiYzM4ZWU2ZjhkYjNlYTkxMmU5ODc2MWNiNTU4YWI5Nzk1ZGIzMDZiNDc0Y6lzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlISW52YWxpZERhdGFFeGNlcHRpb246IENvbnRlbnQgY2h1bmsgcmVxdWVzdCByZXF1aXJlcyBhIG1lc3NhZ2UgaWRlbnRpdHku" + }, + { + "label": "answer_blank_hash.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlksXZlY3Rvci1ibGFuay1oYXNoqWNodW5rSGFzaKCpcmVjb3JkS2V5oLFleHBlY3RlZFNpemVCeXRlc2Q=" + }, + { + "label": "answer_blank_hash.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZLF2ZWN0b3ItYmxhbmstaGFzaKVmb3VuZMKpY2h1bmtIYXNooKlzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlCQXJndW1lbnRFeGNlcHRpb246IEhhc2ggbXVzdCBiZSBub24tZW1wdHkuIChQYXJhbWV0ZXIgJ0NodW5rSGFzaCcp" + }, + { + "label": "answer_whitespace_hash.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlksXZlY3Rvci1zcGFjZS1oYXNoqWNodW5rSGFzaKMgICCpcmVjb3JkS2V5oLFleHBlY3RlZFNpemVCeXRlc2Q=" + }, + { + "label": "answer_whitespace_hash.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZLF2ZWN0b3Itc3BhY2UtaGFzaKVmb3VuZMKpY2h1bmtIYXNooyAgIKlzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlCQXJndW1lbnRFeGNlcHRpb246IEhhc2ggbXVzdCBiZSBub24tZW1wdHkuIChQYXJhbWV0ZXIgJ0NodW5rSGFzaCcp" + }, + { + "label": "answer_prefix_only_hash.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlksnZlY3Rvci1wcmVmaXgtaGFzaKljaHVua0hhc2iqc2hhMjU2OiAgIKlyZWNvcmRLZXmgsWV4cGVjdGVkU2l6ZUJ5dGVzZA==" + }, + { + "label": "answer_prefix_only_hash.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZLJ2ZWN0b3ItcHJlZml4LWhhc2ilZm91bmTCqWNodW5rSGFzaKpzaGEyNTY6ICAgqXNpemVCeXRlcwCncGF5bG9hZMQApWVycm9y2UJBcmd1bWVudEV4Y2VwdGlvbjogSGFzaCBtdXN0IGJlIG5vbi1lbXB0eS4gKFBhcmFtZXRlciAnY2h1bmtIYXNoJyk=" + }, + { + "label": "answer_negative_size.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlkr3ZlY3Rvci1uZWdhdGl2ZaljaHVua0hhc2jZQDU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOpcmVjb3JkS2V52U9tZXNoOmNkbjpjaHVuazo1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjsWV4cGVjdGVkU2l6ZUJ5dGVz/w==" + }, + { + "label": "answer_negative_size.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZK92ZWN0b3ItbmVnYXRpdmWlZm91bmTCqWNodW5rSGFzaNlANTk5M2FjNjA0MDdlODY2MDE4NzNiYzM4ZWU2ZjhkYjNlYTkxMmU5ODc2MWNiNTU4YWI5Nzk1ZGIzMDZiNDc0Y6lzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlgSW52YWxpZERhdGFFeGNlcHRpb246IENETiBhcnRpZmFjdCBjaHVuayBwYXlsb2FkIG1ldGFkYXRhIGRvZXMgbm90IG1hdGNoIGl0cyBtYW5pZmVzdCByZWZlcmVuY2Uu" + }, + { + "label": "answer_record_key_case.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlkr3ZlY3Rvci1rZXktY2FzZaljaHVua0hhc2jZQDU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOpcmVjb3JkS2V52U9NRVNIOkNETjpDSFVOSzo1OTkzQUM2MDQwN0U4NjYwMTg3M0JDMzhFRTZGOERCM0VBOTEyRTk4NzYxQ0I1NThBQjk3OTVEQjMwNkI0NzRDsWV4cGVjdGVkU2l6ZUJ5dGVzzRLf" + }, + { + "label": "answer_record_key_case.response", + "kind": "response", + "messagePackBase64": "h61zY2hlbWFWZXJzaW9u2SJjdWx0bWVzaC5jb250ZW50X2NodW5rX3Jlc3BvbnNlLnYxqW1lc3NhZ2VJZK92ZWN0b3Ita2V5LWNhc2WlZm91bmTCqWNodW5rSGFzaNlANTk5M2FjNjA0MDdlODY2MDE4NzNiYzM4ZWU2ZjhkYjNlYTkxMmU5ODc2MWNiNTU4YWI5Nzk1ZGIzMDZiNDc0Y6lzaXplQnl0ZXMAp3BheWxvYWTEAKVlcnJvctlPSW52YWxpZERhdGFFeGNlcHRpb246IENvbnRlbnQgY2h1bmsgcmVjb3JkIGtleSBkaXNhZ3JlZXMgd2l0aCBpdHMgY29udGVudCBoYXNoLg==" + }, + { + "label": "answer_blank_record_key.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlksHZlY3Rvci1rZXktYmxhbmupY2h1bmtIYXNo2UA1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjqXJlY29yZEtleaMgICCxZXhwZWN0ZWRTaXplQnl0ZXPNEt8=" + }, + { + "label": "answer_blank_record_key.response", + "kind": "response", + "messagePackBase64": "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" + }, + { + "label": "answer_double_prefix.request", + "kind": "request", + "messagePackBase64": "ha1zY2hlbWFWZXJzaW9u2SFjdWx0bWVzaC5jb250ZW50X2NodW5rX3JlcXVlc3QudjGpbWVzc2FnZUlkrXZlY3Rvci1kb3VibGWpY2h1bmtIYXNo2U5zaGEyNTY6c2hhMjU2OjU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOpcmVjb3JkS2V5oLFleHBlY3RlZFNpemVCeXRlc80S3w==" + }, + { + "label": "answer_double_prefix.response", + "kind": "response", + "messagePackBase64": "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" + }, { "label": "response_hash_last_digit", "kind": "response", @@ -55,6 +145,11 @@ "kind": "manifest", "messagePackBase64": "mrVldXJla2EvY29udGVudC12ZWN0b3KlYXNzZXShMdlAZjRhZTJhN2M5NWY0ZDk2NjA1OGY3NWMxMzE4NWFhMGFiNmE5MWZjNWFmYWQ4ODYyOTZlZjJhZWU3NTVhMmFmMc4AFBLfvGFwcGxpY2F0aW9uL3gtY3VsdG5ldC12ZWN0b3LZITIwMjYtMDktMjJUMDA6MDA6MDAuMDAwMDAwMCswMDowMJaU2UBhYTE0NDRiZTRiNjQwOThmNWRkODYzYjViMGFjNTYxNDgwYjNmYjVjNDFmYzA3Y2Y1MGE2MmVkYzk0MTI0YmNjzgAMAADOAAQAANlPbWVzaDpjZG46Y2h1bms6YWExNDQ0YmU0YjY0MDk4ZjVkZDg2M2I1YjBhYzU2MTQ4MGIzZmI1YzQxZmMwN2NmNTBhNjJlZGM5NDEyNGJjY5TZQDMxYTFmOWRlYTAxNjk1NTEwOTJkMDVlOGJmNGE0NDYyMjhjOGMzZWI0YzliNzEzYzY2YWRjYjdmZDUzYzg5YmUAzgAEAADZT21lc2g6Y2RuOmNodW5rOjMxYTFmOWRlYTAxNjk1NTEwOTJkMDVlOGJmNGE0NDYyMjhjOGMzZWI0YzliNzEzYzY2YWRjYjdmZDUzYzg5YmWU2UA1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjzgAUAADNEt/ZT21lc2g6Y2RuOmNodW5rOjU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOU2UBlMzFiZGM2MzU3N2ZlNzZmNjQ0MTAxNGFhYWEyMjI2ZDlmZmNlMTFiNDRkMGQ1MTBjYWRlMTMyYjc5ZmQ3ZDc2zgAEAADOAAQAANlPbWVzaDpjZG46Y2h1bms6ZTMxYmRjNjM1NzdmZTc2ZjY0NDEwMTRhYWFhMjIyNmQ5ZmZjZTExYjQ0ZDBkNTEwY2FkZTEzMmI3OWZkN2Q3NpTZQDI4MzE3MTU4NTlmMDFmM2Y5NjNkZDBmMTE5NGRiZGJiNzYwOTk5NzQyMzAxNWQzMWY2MDc5MTFlMWJmODY0MDLOABAAAM4ABAAA2U9tZXNoOmNkbjpjaHVuazoyODMxNzE1ODU5ZjAxZjNmOTYzZGQwZjExOTRkYmRiYjc2MDk5OTc0MjMwMTVkMzFmNjA3OTExZTFiZjg2NDAylNlAYzdmMWJkZTllMWVmYTdkMTM4NWQ1MWIwNzdlYTg3YjBjMzg2MGQyOGRhNDNkNWQ2ZjIyMWU4NDVjNGMyMzYwZs4ACAAAzgAEAADZT21lc2g6Y2RuOmNodW5rOmM3ZjFiZGU5ZTFlZmE3ZDEzODVkNTFiMDc3ZWE4N2IwYzM4NjBkMjhkYTQzZDVkNmYyMjFlODQ1YzRjMjM2MGaQgA==" }, + { + "label": "manifest_metadata_order", + "kind": "manifest", + "messagePackBase64": "mrVldXJla2EvY29udGVudC12ZWN0b3KlYXNzZXShMdlAZjRhZTJhN2M5NWY0ZDk2NjA1OGY3NWMxMzE4NWFhMGFiNmE5MWZjNWFmYWQ4ODYyOTZlZjJhZWU3NTVhMmFmMc4AFBLfvGFwcGxpY2F0aW9uL3gtY3VsdG5ldC12ZWN0b3LZITIwMjYtMDktMjJUMDA6MDA6MDAuMDAwMDAwMCswMDowMJaU2UAzMWExZjlkZWEwMTY5NTUxMDkyZDA1ZThiZjRhNDQ2MjI4YzhjM2ViNGM5YjcxM2M2NmFkY2I3ZmQ1M2M4OWJlAM4ABAAA2U9tZXNoOmNkbjpjaHVuazozMWExZjlkZWEwMTY5NTUxMDkyZDA1ZThiZjRhNDQ2MjI4YzhjM2ViNGM5YjcxM2M2NmFkY2I3ZmQ1M2M4OWJllNlAZTMxYmRjNjM1NzdmZTc2ZjY0NDEwMTRhYWFhMjIyNmQ5ZmZjZTExYjQ0ZDBkNTEwY2FkZTEzMmI3OWZkN2Q3Ns4ABAAAzgAEAADZT21lc2g6Y2RuOmNodW5rOmUzMWJkYzYzNTc3ZmU3NmY2NDQxMDE0YWFhYTIyMjZkOWZmY2UxMWI0NGQwZDUxMGNhZGUxMzJiNzlmZDdkNzaU2UBjN2YxYmRlOWUxZWZhN2QxMzg1ZDUxYjA3N2VhODdiMGMzODYwZDI4ZGE0M2Q1ZDZmMjIxZTg0NWM0YzIzNjBmzgAIAADOAAQAANlPbWVzaDpjZG46Y2h1bms6YzdmMWJkZTllMWVmYTdkMTM4NWQ1MWIwNzdlYTg3YjBjMzg2MGQyOGRhNDNkNWQ2ZjIyMWU4NDVjNGMyMzYwZpTZQGFhMTQ0NGJlNGI2NDA5OGY1ZGQ4NjNiNWIwYWM1NjE0ODBiM2ZiNWM0MWZjMDdjZjUwYTYyZWRjOTQxMjRiY2POAAwAAM4ABAAA2U9tZXNoOmNkbjpjaHVuazphYTE0NDRiZTRiNjQwOThmNWRkODYzYjViMGFjNTYxNDgwYjNmYjVjNDFmYzA3Y2Y1MGE2MmVkYzk0MTI0YmNjlNlAMjgzMTcxNTg1OWYwMWYzZjk2M2RkMGYxMTk0ZGJkYmI3NjA5OTk3NDIzMDE1ZDMxZjYwNzkxMWUxYmY4NjQwMs4AEAAAzgAEAADZT21lc2g6Y2RuOmNodW5rOjI4MzE3MTU4NTlmMDFmM2Y5NjNkZDBmMTE5NGRiZGJiNzYwOTk5NzQyMzAxNWQzMWY2MDc5MTFlMWJmODY0MDKU2UA1OTkzYWM2MDQwN2U4NjYwMTg3M2JjMzhlZTZmOGRiM2VhOTEyZTk4NzYxY2I1NThhYjk3OTVkYjMwNmI0NzRjzgAUAADNEt/ZT21lc2g6Y2RuOmNodW5rOjU5OTNhYzYwNDA3ZTg2NjAxODczYmMzOGVlNmY4ZGIzZWE5MTJlOTg3NjFjYjU1OGFiOTc5NWRiMzA2YjQ3NGOQg6R6ZXRhoTGlYWxwaGGhMqNtaWShMw==" + }, { "label": "manifest_empty_body", "kind": "manifest", diff --git a/packages/cultnet-rs/src/content.rs b/packages/cultnet-rs/src/content.rs index bbf460b9..843d4b86 100644 --- a/packages/cultnet-rs/src/content.rs +++ b/packages/cultnet-rs/src/content.rs @@ -6,8 +6,6 @@ //! This is the only owner of these rules in Rust. A consumer hands `fetch_content` a transport //! closure and gets verified bytes; it never hashes, chunks or validates a manifest itself. -use std::collections::BTreeMap; - use anyhow::{Result, anyhow, bail}; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; @@ -44,7 +42,9 @@ pub struct CultMeshCdnArtifactManifest { pub created_at_utc: String, pub chunks: Vec, pub tags: Vec, - pub metadata: BTreeMap, + /// Caller metadata in wire order. The reference writes a `Dictionary` in insertion order and + /// refuses a duplicate key at read, so this keeps the order it was read in and refuses a duplicate. + pub metadata: Vec<(String, String)>, } // The tuple mirrors: `to_vec_named` would write a map for a named-field struct, but a tuple @@ -63,9 +63,46 @@ struct ManifestWire( String, Vec, Vec, - BTreeMap, + #[serde(with = "ordered_map")] Vec<(String, String)>, ); +/// A string map that keeps its key order and refuses a duplicate key, as `Dictionary` +/// deserialises. `Vec<(String, String)>` is the in-memory shape; the wire shape is a msgpack map. +mod ordered_map { + use std::fmt; + + use serde::de::{self, MapAccess, Visitor}; + use serde::{Deserializer, Serializer}; + + pub fn serialize(pairs: &[(String, String)], serializer: S) -> Result { + serializer.collect_map(pairs.iter().map(|(key, value)| (key, value))) + } + + pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result, D::Error> { + struct Pairs; + impl<'de> Visitor<'de> for Pairs { + type Value = Vec<(String, String)>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map of strings") + } + + fn visit_map>(self, mut map: A) -> Result { + let mut seen = std::collections::HashSet::new(); + let mut pairs = Vec::new(); + while let Some((key, value)) = map.next_entry::()? { + if !seen.insert(key.clone()) { + return Err(de::Error::custom(format!("duplicate metadata key '{key}'"))); + } + pairs.push((key, value)); + } + Ok(pairs) + } + } + deserializer.deserialize_map(Pairs) + } +} + impl From for ChunkRefWire { fn from(value: CultMeshCdnChunkRef) -> Self { Self(value.chunk_hash, value.offset, value.size_bytes, value.record_key) @@ -138,6 +175,15 @@ pub fn normalize_hash(hash: &str) -> Result { Ok(stripped.trim().to_lowercase()) } +/// A hash the client will put on the wire or compare against: normalized and not empty. +fn non_empty_hash(hash: &str) -> Result { + let normalized = normalize_hash(hash)?; + if normalized.is_empty() { + bail!("Hash must be non-empty."); + } + Ok(normalized) +} + /// `CultMeshCdn.PackArtifact`: splits `bytes` into content-addressed chunks and builds the manifest. /// An empty body packs as one zero-length chunk, as the reference does. pub fn pack_content( @@ -188,7 +234,7 @@ pub fn pack_content( created_at_utc: created_at_utc.to_string(), chunks: refs, tags: Vec::new(), - metadata: BTreeMap::new(), + metadata: Vec::new(), }; validate_manifest(&manifest)?; Ok((manifest, chunks)) @@ -277,13 +323,17 @@ pub fn answer_content_chunk_request<'a>( if message_id.trim().is_empty() { return Err("InvalidDataException: Content chunk request requires a message identity.".to_string()); } - let hash = normalize_hash(chunk_hash) - .map_err(|_| "ArgumentException: Hash must be non-empty. (Parameter 'ChunkHash')".to_string())?; - if !record_key.trim().is_empty() && *record_key != chunk_record_key(&hash) { + // The handler normalises the wire hash, then `CreateRecordKey` normalises that result again + // (and spells its parameter `chunkHash`); the lookup, the size check and the hash check all + // use the second result, and the answer echoes the first. + let blank = |parameter: &str| format!("ArgumentException: Hash must be non-empty. (Parameter '{parameter}')"); + let hash = normalize_hash(chunk_hash).map_err(|_| blank("ChunkHash"))?; + let canonical = normalize_hash(&hash).map_err(|_| blank("chunkHash"))?; + if !record_key.trim().is_empty() && *record_key != chunk_record_key(&canonical) { return Err("InvalidDataException: Content chunk record key disagrees with its content hash.".to_string()); } - let payload = lookup(&hash).ok_or_else(|| "FileNotFoundException: Content chunk is not available.".to_string())?; - validate_chunk(&hash, *expected_size_bytes, &hash, payload.len() as i64, payload) + let payload = lookup(&canonical).ok_or_else(|| "FileNotFoundException: Content chunk is not available.".to_string())?; + validate_chunk(&canonical, *expected_size_bytes, &canonical, payload.len() as i64, payload) .map_err(|error| format!("InvalidDataException: {error}"))?; Ok((hash, payload.to_vec())) })(); @@ -323,9 +373,20 @@ pub fn fetch_content( manifest.size_bytes ); } + // Everything the client will send or compare is settled before the first request. A zero-size + // chunk is legal only as an empty body's single chunk (the reference packs it so); anywhere else + // it is a request that yields nothing, and a manifest of them is a request flood. + let ordered = in_offset_order(manifest); + if ordered.len() > 1 && ordered.iter().any(|chunk| chunk.size_bytes == 0) { + bail!("CDN artifact has a zero-size chunk beside other chunks."); + } + let content_hash = non_empty_hash(&manifest.content_hash)?; + let hashes = ordered + .iter() + .map(|chunk| non_empty_hash(&chunk.chunk_hash)) + .collect::>>()?; let mut body = Vec::new(); - for chunk in in_offset_order(manifest) { - let hash = normalize_hash(&chunk.chunk_hash)?; + for (chunk, hash) in ordered.into_iter().zip(hashes) { let message_id = uuid::Uuid::new_v4().simple().to_string(); let record_key = if chunk.record_key.trim().is_empty() { chunk_record_key(&hash) @@ -358,7 +419,7 @@ pub fn fetch_content( validate_chunk(&hash, chunk.size_bytes, &chunk_hash, i64::from(size_bytes), &payload)?; body.extend_from_slice(&payload); } - if sha256_hex(&body) != normalize_hash(&manifest.content_hash)? { + if sha256_hex(&body) != content_hash { bail!("CDN artifact content hash does not match its manifest."); } Ok(body) diff --git a/packages/cultnet-rs/src/contracts.rs b/packages/cultnet-rs/src/contracts.rs index 038b0708..0925215e 100644 --- a/packages/cultnet-rs/src/contracts.rs +++ b/packages/cultnet-rs/src/contracts.rs @@ -801,40 +801,10 @@ fn validate_message(message: &CultNetMessage) -> Result<()> { validate_shard_descriptor(shard)?; } } - CultNetMessage::ContentChunkRequest { - message_id, - chunk_hash, - record_key: _, - expected_size_bytes, - } => { - require_non_empty(message_id, "messageId")?; - if crate::normalize_hash(chunk_hash)?.is_empty() { - return Err(anyhow!("CultNet field chunkHash must be non-empty")); - } - if *expected_size_bytes < 0 { - return Err(anyhow!("CultNet field expectedSizeBytes must not be negative")); - } - } - CultNetMessage::ContentChunkResponse { - message_id, - found, - chunk_hash: _, - size_bytes, - payload, - error, - } => { - require_non_empty(message_id, "messageId")?; - if *found { - if i64::try_from(payload.len()).ok() != Some(i64::from(*size_bytes)) { - return Err(anyhow!("CultNet field payload length must equal sizeBytes")); - } - if !error.is_empty() { - return Err(anyhow!("CultNet field error must be empty when found")); - } - } else if !payload.is_empty() { - return Err(anyhow!("CultNet field payload must be empty when not found")); - } - } + // The reference's serializer accepts any content chunk message. It refuses a bad request in + // its handler and answers `found: false` (`answer_content_chunk_request`); a bad response is + // refused by `fetch_content`'s verification. Refusing either here would leave a peer in silence. + CultNetMessage::ContentChunkRequest { .. } | CultNetMessage::ContentChunkResponse { .. } => {} CultNetMessage::OperationRequest { message_id, service_id, diff --git a/packages/cultnet-rs/tests/content.rs b/packages/cultnet-rs/tests/content.rs index 363a600d..e4edb0bf 100644 --- a/packages/cultnet-rs/tests/content.rs +++ b/packages/cultnet-rs/tests/content.rs @@ -61,6 +61,24 @@ fn manifest_bytes(manifest: &CultMeshCdnArtifactManifest) -> Vec { rmp_serde::to_vec_named(manifest).expect("encodes") } +fn decode_manifest(bytes: &[u8]) -> CultMeshCdnArtifactManifest { + rmp_serde::from_slice(bytes).expect("decodes") +} + +/// The manifest's bytes with its metadata map replaced by `pairs`, written in exactly that order +/// (and with duplicates, if given): what a peer that is not this crate can put on the wire. +fn manifest_with_metadata(manifest: &CultMeshCdnArtifactManifest, pairs: &[(&str, &str)]) -> Vec { + let encoded = manifest_bytes(manifest); + let mut value = rmpv::decode::read_value(&mut encoded.as_slice()).expect("a msgpack value"); + let rmpv::Value::Array(fields) = &mut value else { + panic!("the manifest is a positional array"); + }; + fields[9] = rmpv::Value::Map(pairs.iter().map(|(k, v)| (rmpv::Value::from(*k), rmpv::Value::from(*v))).collect()); + let mut out = Vec::new(); + rmpv::encode::write_value(&mut out, &value).expect("writes"); + out +} + fn request(id: &str, hash: &str, key: &str, size: i32) -> CultNetMessage { CultNetMessage::ContentChunkRequest { message_id: id.to_string(), @@ -171,6 +189,21 @@ fn local_vectors() -> Vec { request("vector-key", &last.chunk_hash, "mesh:cdn:chunk:other", last_size), ), ("answer_size_mismatch", request("vector-size", &last.chunk_hash, &key, last_size - 1)), + ("answer_blank_message_id", request("", &last.chunk_hash, &key, last_size)), + ("answer_whitespace_message_id", request(" ", &last.chunk_hash, &key, last_size)), + ("answer_blank_hash", request("vector-blank-hash", "", "", 100)), + ("answer_whitespace_hash", request("vector-space-hash", " ", "", 100)), + ("answer_prefix_only_hash", request("vector-prefix-hash", "sha256: ", "", 100)), + ("answer_negative_size", request("vector-negative", &last.chunk_hash, &key, -1)), + ( + "answer_record_key_case", + request("vector-key-case", &last.chunk_hash, &key.to_uppercase(), last_size), + ), + ("answer_blank_record_key", request("vector-key-blank", &last.chunk_hash, " ", last_size)), + ( + "answer_double_prefix", + request("vector-double", &format!("sha256:sha256:{}", last.chunk_hash), "", last_size), + ), ]; for (name, request) in &answers { push_message(format!("{name}.request"), "request", request); @@ -200,6 +233,8 @@ fn local_vectors() -> Vec { let mut shuffled = manifest.clone(); shuffled.chunks = [3, 0, 5, 1, 4, 2].iter().map(|&i| manifest.chunks[i].clone()).collect(); push_manifest("manifest_out_of_order", &shuffled); + let tagged = decode_manifest(&manifest_with_metadata(&manifest, &[("zeta", "1"), ("alpha", "2"), ("mid", "3")])); + push_manifest("manifest_metadata_order", &tagged); push_manifest("manifest_empty_body", &pack(&[]).0); vectors } @@ -479,7 +514,7 @@ fn answer_serves_found_false_with_the_reference_error_spelling() { .expect("paired response"); assert_eq!(&wire(&answer), expected_bytes, "{name}: answer differs from the reference's"); let (_, found, _, payload, error) = response_of(&answer); - if name == "answer_found" { + if ["answer_found", "answer_blank_record_key", "answer_double_prefix"].contains(&name) { assert!(found && error.is_empty() && !payload.is_empty()); } else { assert!(!found && payload.is_empty(), "{name}"); @@ -487,28 +522,7 @@ fn answer_serves_found_false_with_the_reference_error_spelling() { } judged += 1; } - assert_eq!(judged, 4); -} - -#[test] -fn content_messages_refuse_what_the_reference_never_produces() { - let refused = |message: CultNetMessage| assert!(encode_cultnet_message_for_wire(&message, SCHEMA_V0).is_err(), "{message:?}"); - refused(request("", "abc", "", 1)); - refused(request("m", "sha256: ", "", 1)); - refused(request("m", "abc", "", -1)); - let response = |found: bool, size: i32, payload: &[u8], error: &str| CultNetMessage::ContentChunkResponse { - message_id: "m".to_string(), - found, - chunk_hash: "abc".to_string(), - size_bytes: size, - payload: payload.to_vec(), - error: error.to_string(), - }; - refused(response(true, 3, &[1, 2], "")); - refused(response(true, 2, &[1, 2], "boom")); - refused(response(false, 0, &[1], "boom")); - assert!(encode_cultnet_message_for_wire(&response(true, 2, &[1, 2], ""), SCHEMA_V0).is_ok()); - assert!(encode_cultnet_message_for_wire(&response(false, 0, &[], "boom"), SCHEMA_V0).is_ok()); + assert_eq!(judged, 13); } #[test] @@ -518,3 +532,236 @@ fn gamecult_networking_contract_refuses_content_messages() { assert!(encode_cultnet_message_for_wire(&message, legacy).is_err()); assert!(decode_cultnet_message_from_slice(&wire(&message), legacy).is_err()); } + +// ------------------------------------------------------------------------------------------ +// BP-1 fixes +// ------------------------------------------------------------------------------------------ + +fn chunk_ref(hash: &str, offset: i64, size: i32) -> cultnet_rs::CultMeshCdnChunkRef { + cultnet_rs::CultMeshCdnChunkRef { + chunk_hash: hash.to_string(), + offset, + size_bytes: size, + record_key: String::new(), + } +} + +/// A manifest with the given chunk list and stated size, everything else from a real pack. +fn manifest_of(size: i64, chunks: Vec) -> CultMeshCdnArtifactManifest { + let mut manifest = pack(&[]).0; + manifest.size_bytes = size; + manifest.chunks = chunks; + manifest +} + +// F1: a zero-size chunk is legal only as an empty body's single chunk. +#[test] +fn a_zero_size_chunk_flood_is_refused_before_any_request() { + let (empty, empty_chunks) = pack(&[]); + let empty_store = store(&empty_chunks); + let flood = manifest_of(0, (0..100_000).map(|_| chunk_ref(&empty.content_hash, 0, 0)).collect()); + validate_manifest(&flood).expect("the shared shape rule accepts it, as the reference does"); + let calls = std::cell::Cell::new(0); + assert!(fetch_content(&flood, u64::MAX, serving(&empty_store, &calls)).is_err()); + assert_eq!(calls.get(), 0, "100,000 empty chunks must not become 100,000 requests"); + + // A zero-size chunk beside real ones is refused too, so skipping it is never the client's job. + let (good, chunks) = pack(&body()); + let body_store = store(&chunks); + let mut zero_inside = good.clone(); + let boundary = zero_inside.chunks[2].offset; + zero_inside.chunks.insert(2, chunk_ref(&empty.content_hash, boundary, 0)); + validate_manifest(&zero_inside).expect("shape-valid"); + let calls = std::cell::Cell::new(0); + assert!(fetch_content(&zero_inside, u64::MAX, serving(&body_store, &calls)).is_err()); + assert_eq!(calls.get(), 0); + + // An empty body still fetches, through its one zero-length chunk. + let calls = std::cell::Cell::new(0); + assert_eq!(fetch_content(&empty, 0, serving(&empty_store, &calls)).expect("fetches"), Vec::::new()); + assert_eq!(calls.get(), 1); +} + +// F2, F5: every bad request is answered, in the reference's validation order and spelling. The +// byte-identity against the reference server's own answers is `answer_serves_found_false_...`. +#[test] +fn a_bad_request_is_answered_never_dropped() { + let (_, chunks) = pack(&body()); + let store = store(&chunks); + let last = chunks.last().unwrap(); + let size = last.payload.len() as i32; + let size_mismatch = "InvalidDataException: CDN artifact chunk payload metadata does not match its manifest reference."; + for (label, bad, spelling) in [ + ( + "blank id", + request("", &last.chunk_hash, "", size), + "InvalidDataException: Content chunk request requires a message identity.", + ), + ("blank hash", request("m", "", "", size), "ArgumentException: Hash must be non-empty. (Parameter 'ChunkHash')"), + ( + "prefix-only hash", + request("m", "sha256: ", "", size), + "ArgumentException: Hash must be non-empty. (Parameter 'chunkHash')", + ), + ("negative size", request("m", &last.chunk_hash, "", -1), size_mismatch), + ] { + let answer = answer_content_chunk_request(&bad, lookup_in(&store)); + let (_, found, _, payload, error) = response_of(&answer); + assert!(!found && payload.is_empty(), "{label}"); + assert_eq!(error, spelling, "{label}"); + // And both travel: neither the request nor its answer is stopped at decode or encode. + assert_eq!(unwire(&wire(&bad)).expect("the request decodes"), bad, "{label}"); + assert_eq!(unwire(&wire(&answer)).expect("the answer encodes and decodes"), answer, "{label}"); + } +} + +// F3: metadata keeps the order it was read in and refuses a duplicate key. +#[test] +fn manifest_metadata_keeps_wire_order_and_refuses_a_duplicate_key() { + let reference = read_vectors("content-vectors.cs-written.json"); + let (_, _, bytes) = reference.iter().find(|(l, _, _)| l == "manifest_metadata_order").expect("vector"); + let decoded = decode_manifest(bytes); + assert_eq!(&manifest_bytes(&decoded), bytes, "zeta, alpha, mid re-encode as zeta, alpha, mid"); + + let base = pack(&body()).0; + let duplicated = manifest_with_metadata(&base, &[("k", "1"), ("other", "2"), ("k", "3")]); + assert!(rmp_serde::from_slice::(&duplicated).is_err()); + let unique = manifest_with_metadata(&base, &[("k", "1"), ("other", "2")]); + assert_eq!(manifest_bytes(&decode_manifest(&unique)), unique); +} + +// F4: hashes are settled before the first request. +#[test] +fn a_blank_hash_is_refused_before_any_request() { + let (good, chunks) = pack(&body()); + let store = store(&chunks); + let mut blank_content = good.clone(); + blank_content.content_hash = " ".to_string(); + let mut prefix_content = good.clone(); + prefix_content.content_hash = "sha256: ".to_string(); + let mut blank_chunk = good.clone(); + blank_chunk.chunks[3].chunk_hash = " ".to_string(); + let mut prefix_chunk = good.clone(); + prefix_chunk.chunks[3].chunk_hash = "SHA256: ".to_string(); + for (label, manifest) in [ + ("blank content hash", blank_content), + ("prefix-only content hash", prefix_content), + ("blank chunk hash at 3", blank_chunk), + ("prefix-only chunk hash at 3", prefix_chunk), + ] { + let calls = std::cell::Cell::new(0); + assert!(fetch_content(&manifest, u64::MAX, serving(&store, &calls)).is_err(), "{label}"); + assert_eq!(calls.get(), 0, "{label}: refused before any request"); + } +} + +// F6: `pack_content` refuses a chunk size the reference's int cannot hold, without panicking. +#[test] +fn pack_content_refuses_an_unusable_chunk_size() { + for size in [0usize, i32::MAX as usize + 1, usize::MAX] { + let refused = std::panic::catch_unwind(|| pack_content("a", "", "", "", "", b"abc", size)); + assert!(matches!(refused, Ok(Err(_))), "chunk size {size} must be refused cleanly"); + } + let (manifest, _) = + pack_content("a", "", "", "", "", b"abc", i32::MAX as usize).expect("i32::MAX is a valid chunk size"); + assert_eq!(manifest.chunks.len(), 1); +} + +// F6: `PackArtifact` defaults a blank kind and mime type and otherwise uses the value untouched. +#[test] +fn pack_defaults_only_a_blank_kind_and_mime_type_and_never_trims() { + let packed = |kind: &str, mime: &str| pack_content("a", kind, "v", mime, CREATED, b"abc", 2).expect("packs").0; + for blank in ["", " ", "\t \n"] { + let manifest = packed(blank, blank); + assert_eq!( + (manifest.kind.as_str(), manifest.mime_type.as_str()), + ("asset", "application/octet-stream"), + "{blank:?}" + ); + } + let manifest = packed(" build ", " text/plain "); + assert_eq!((manifest.kind.as_str(), manifest.mime_type.as_str()), (" build ", " text/plain ")); +} + +/// The honest answer to `request`, taken apart so a test can lie in one field. +fn honest(request: &CultNetMessage, store: &HashMap>) -> (String, bool, String, i32, Vec, String) { + match answer_content_chunk_request(request, lookup_in(store)) { + CultNetMessage::ContentChunkResponse { message_id, found, chunk_hash, size_bytes, payload, error } => { + (message_id, found, chunk_hash, size_bytes, payload, error) + } + other => panic!("{other:?}"), + } +} + +// F6: the two halves of the per-chunk check, each on its own. +#[test] +fn a_chunk_whose_length_or_claim_disagrees_with_the_manifest_is_refused() { + let (manifest, chunks) = pack(&body()); + let store = store(&chunks); + // Each lie maps (honest size, honest payload) to (claimed size, payload served). + type Lie = fn(i32, Vec) -> (i32, Vec); + let lies: [(&str, Lie); 4] = [ + ("a payload of the claimed length that is not the manifest's length", |size, mut p| { + p.truncate(p.len() - 1); + (size - 1, p) + }), + ("a payload whose length is not its claimed size, the claim being the manifest's", |size, mut p| { + p.truncate(p.len() - 1); + (size, p) + }), + ("the right payload under a wrong claimed size", |size, p| (size - 1, p)), + ("a longer payload of its claimed length", |size, mut p| { + p.push(0); + (size + 1, p) + }), + ]; + for (label, lie) in lies { + let error = fetch_content(&manifest, u64::MAX, |message| { + let (message_id, found, chunk_hash, honest_size, payload, error) = honest(&message, &store); + let (size_bytes, payload) = lie(honest_size, payload); + Ok(CultNetMessage::ContentChunkResponse { message_id, found, chunk_hash, size_bytes, payload, error }) + }) + .expect_err(label); + assert!(error.to_string().contains("payload metadata does not match"), "{label}: {error}"); + } +} + +// F6: `[5@0, 0@0]` is not contiguous under the reference's stable sort by offset alone. +#[test] +fn equal_offsets_keep_their_manifest_order() { + let hash = "0".repeat(64); + let five_then_zero = manifest_of(5, vec![chunk_ref(&hash, 0, 5), chunk_ref(&hash, 0, 0)]); + assert!(validate_manifest(&five_then_zero).is_err(), "the stable sort keeps 5@0 first, so 0@0 lands at offset 5"); + let zero_then_five = manifest_of(5, vec![chunk_ref(&hash, 0, 0), chunk_ref(&hash, 0, 5)]); + validate_manifest(&zero_then_five).expect("0@0 first leaves 5@0 at offset 0"); +} + +// F6: what goes on the wire is the normalized hash and the canonical record key. +#[test] +fn the_client_sends_the_normalized_hash_and_canonical_record_key() { + let (mut manifest, chunks) = pack(&body()); + let store = store(&chunks); + let honest_hashes: Vec = manifest.chunks.iter().map(|c| c.chunk_hash.clone()).collect(); + manifest.content_hash = format!("SHA256:{}", manifest.content_hash.to_uppercase()); + for (index, chunk) in manifest.chunks.iter_mut().enumerate() { + chunk.chunk_hash = format!("sha256:{}", chunk.chunk_hash.to_uppercase()); + // Alternate chunks name their key; the rest leave it blank for the client to derive. + chunk.record_key = + if index % 2 == 0 { format!("mesh:cdn:chunk:{}", honest_hashes[index]) } else { " ".to_string() }; + } + let mut sent = Vec::new(); + let fetched = fetch_content(&manifest, u64::MAX, |message| { + sent.push(message.clone()); + Ok(answer_content_chunk_request(&message, lookup_in(&store))) + }) + .expect("fetches"); + assert_eq!(fetched, body()); + assert_eq!(sent.len(), honest_hashes.len()); + for (message, hash) in sent.iter().zip(&honest_hashes) { + let CultNetMessage::ContentChunkRequest { chunk_hash, record_key, .. } = message else { + panic!("not a request"); + }; + assert_eq!(chunk_hash, hash, "the normalized hash is what is sent"); + assert_eq!(record_key, &format!("mesh:cdn:chunk:{hash}"), "and the canonical key"); + } +} diff --git a/tests/GameCult.Mesh.Tests/CultMeshContentVectorTests.cs b/tests/GameCult.Mesh.Tests/CultMeshContentVectorTests.cs index 2e156891..6c5763bb 100644 --- a/tests/GameCult.Mesh.Tests/CultMeshContentVectorTests.cs +++ b/tests/GameCult.Mesh.Tests/CultMeshContentVectorTests.cs @@ -164,6 +164,16 @@ public sealed class CultMeshContentVectorTests AddAnswer("answer_not_found", Request("vector-missing", new string('0', 64), string.Empty, 100)); AddAnswer("answer_record_key_disagrees", Request("vector-key", last.ChunkHash, "mesh:cdn:chunk:other", last.SizeBytes)); AddAnswer("answer_size_mismatch", Request("vector-size", last.ChunkHash, key, last.SizeBytes - 1)); + // Requests the reference refuses in its handler, never at deserialisation: each is answered. + AddAnswer("answer_blank_message_id", Request(string.Empty, last.ChunkHash, key, last.SizeBytes)); + AddAnswer("answer_whitespace_message_id", Request(" ", last.ChunkHash, key, last.SizeBytes)); + AddAnswer("answer_blank_hash", Request("vector-blank-hash", string.Empty, string.Empty, 100)); + AddAnswer("answer_whitespace_hash", Request("vector-space-hash", " ", string.Empty, 100)); + AddAnswer("answer_prefix_only_hash", Request("vector-prefix-hash", "sha256: ", string.Empty, 100)); + AddAnswer("answer_negative_size", Request("vector-negative", last.ChunkHash, key, -1)); + AddAnswer("answer_record_key_case", Request("vector-key-case", last.ChunkHash, key.ToUpperInvariant(), last.SizeBytes)); + AddAnswer("answer_blank_record_key", Request("vector-key-blank", last.ChunkHash, " ", last.SizeBytes)); + AddAnswer("answer_double_prefix", Request("vector-double", "sha256:sha256:" + last.ChunkHash, string.Empty, last.SizeBytes)); AddResponse("response_hash_last_digit", new CultMeshContentChunkResponseMessage { MessageId = "vector-digit", @@ -184,6 +194,9 @@ public sealed class CultMeshContentVectorTests var shuffled = CultMeshCdn.PackArtifact(ArtifactId, Body(), Options()).Manifest; shuffled.Chunks = new[] { 3, 0, 5, 1, 4, 2 }.Select(i => shuffled.Chunks[i]).ToArray(); AddManifest("manifest_out_of_order", shuffled); + var tagged = CultMeshCdn.PackArtifact(ArtifactId, Body(), Options()).Manifest; + tagged.Metadata = new Dictionary { ["zeta"] = "1", ["alpha"] = "2", ["mid"] = "3" }; + AddManifest("manifest_metadata_order", tagged); AddManifest("manifest_empty_body", CultMeshCdn.PackArtifact(ArtifactId, Array.Empty(), Options()).Manifest); return vectors; }