tx · GPDrfDQ2Jpsvk5nSwYoCMcd5MEHcZSCcD2kGPSNpoy1M 3MsqKJ6o1ABE37676cHHBxJRs6huYTt72ch: -0.03900000 Waves 2024.07.17 11:33 [3197802] smart account 3MsqKJ6o1ABE37676cHHBxJRs6huYTt72ch > SELF 0.00000000 Waves
{ "type": 13, "id": "GPDrfDQ2Jpsvk5nSwYoCMcd5MEHcZSCcD2kGPSNpoy1M", "fee": 3900000, "feeAssetId": null, "timestamp": 1721205202912, "version": 2, "chainId": 84, "sender": "3MsqKJ6o1ABE37676cHHBxJRs6huYTt72ch", "senderPublicKey": "3xjN6fjYDXBGUE1mcRw2Fvr4R6tEZnuJA98QFGF99sXd", "proofs": [ "QoQeusH8EtnYwzXqbgxXGrJcMojwK5Tuf7siG3cDENWuqH6KU1zqjkiYNZPYH46mrhXeXPWzaLVT5wymvA7Fe76" ], "script": "base64:CAJbCAISBAoCCAgSBQoDCAgIEgUKAwgIARIGCgQICAEIEgUKAwgIARIGCgQICAEIEgYKBAEICAESBwoFAQgIAQgSAwoBAhIAEgYKBAgSAQESBgoECAEICBIECgIBCE4AB0lOVF9NQVgA//////////9/AAVXQVZFUwCAwtcvAAtNSU5fQkFMQU5DRQkAaAIAoJwBBQVXQVZFUwADU0VQAgEsAA9CTE9DS19IQVNIX1NJWkUAIAAMQUREUkVTU19TSVpFABoAFFBVQkxJQ19LRVlfSEFTSF9TSVpFABQACXplcm9lc1N0cgKACDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAEHRoaXNFcG9jaERhdGFLZXkCDXRoaXNFcG9jaERhdGEADGFsbE1pbmVyc0tleQIJYWxsTWluZXJzAA5tYWluQ2hhaW5JZEtleQILbWFpbkNoYWluSWQADmxhc3RDaGFpbklkS2V5AgtsYXN0Q2hhaW5JZAAXZmlyc3RWYWxpZEFsdENoYWluSWRLZXkCFGZpcnN0VmFsaWRBbHRDaGFpbklkAA5taW5lclJld2FyZEtleQILbWluZXJSZXdhcmQAGXN0YWtpbmdDb250cmFjdEFkZHJlc3NLZXkCFnN0YWtpbmdDb250cmFjdEFkZHJlc3MACmJsb2NrTWV0YUsCCGJsb2NrXzB4ABFmaW5hbGl6ZWRCbG9ja0tleQIOZmluYWxpemVkQmxvY2sACnRva2VuSWRLZXkCB3Rva2VuSWQAEmVsQnJpZGdlQWRkcmVzc0tleQIPZWxCcmlkZ2VBZGRyZXNzABNwcmV2UmFuZGFvSGVpZ2h0S2V5AhBwcmV2UmFuZGFvSGVpZ2h0ABdlbFRvQ2xUcmFuc2ZlcnNFcG9jaEtleQIUZWxUb0NsVHJhbnNmZXJzRXBvY2gBA3BhZAEBaQQBcwkApAMBBQFpBAckbWF0Y2gwCQCxAgEFAXMDCQAAAgABBQckbWF0Y2gwCQCsAgICBzAwMDAwMDAFAXMDCQAAAgACBQckbWF0Y2gwCQCsAgICBjAwMDAwMAUBcwMJAAACAAMFByRtYXRjaDAJAKwCAgIFMDAwMDAFAXMDCQAAAgAEBQckbWF0Y2gwCQCsAgICBDAwMDAFAXMDCQAAAgAFBQckbWF0Y2gwCQCsAgICAzAwMAUBcwMJAAACAAYFByRtYXRjaDAJAKwCAgICMDAFAXMDCQAAAgAHBQckbWF0Y2gwCQCsAgICATAFAXMFAXMBF2Jsb2NrRWxUb0NsVHJhbnNmZXJzS2V5AQxibG9ja0hhc2hIZXgJAKwCAgISZWxUb0NsVHJhbnNmZXJzXzB4BQxibG9ja0hhc2hIZXgBDGVwb2NoTWV0YUtleQEFZXBvY2gJAKwCAgIGZXBvY2hfCQEDcGFkAQUFZXBvY2gBFGNoYWluRmlyc3RCbG9ja0lkS2V5AQdjaGFpbklkCQCsAgIJAKwCAgIFY2hhaW4JAKQDAQUHY2hhaW5JZAIKRmlyc3RCbG9jawEMY2hhaW5NZXRhS2V5AQdjaGFpbklkCQCsAgICBmNoYWluXwkBA3BhZAEFB2NoYWluSWQBEmNoYWluTGFzdEhlaWdodEtleQIHY2hhaW5JZAVtaW5lcgkArAICCQCsAgIJAKwCAgIGY2hhaW5fCQEDcGFkAQUHY2hhaW5JZAIBXwkApQgBBQVtaW5lcgEUY2hhaW5Gb3JrZWRIZWlnaHRLZXkBB2NoYWluSWQJAKwCAgkArAICAgZjaGFpbl8JAQNwYWQBBQdjaGFpbklkAgxGb3JrZWRIZWlnaHQBDXN1cHBvcnRlcnNLZXkBB2NoYWluSWQJAKwCAgkArAICAgVjaGFpbgkApAMBBQdjaGFpbklkAgpTdXBwb3J0ZXJzARVtaW5lclJld2FyZEFkZHJlc3NLZXkBCW1pbmVyQWRkcgkArAICCQCsAgICBm1pbmVyXwUJbWluZXJBZGRyAg5fUmV3YXJkQWRkcmVzcwEKbWluZXJQa0tleQENcmV3YXJkQWRkcmVzcwkArAICCQCsAgICCG1pbmVyXzB4BQ1yZXdhcmRBZGRyZXNzAgNfUEsBD21pbmVyQ2hhaW5JZEtleQEFbWluZXIJAKwCAgkArAICAgZtaW5lcl8JAKUIAQUFbWluZXICCF9DaGFpbklkABRlbFRvQ2xUcmFuc2ZlcnNFcG9jaAkBC3ZhbHVlT3JFbHNlAgkAmggCBQR0aGlzBRdlbFRvQ2xUcmFuc2ZlcnNFcG9jaEtleQUHSU5UX01BWAEecmVxdWlyZUVsVG9DbFRyYW5zZmVyc0Rpc2FibGVkAAMJAGYCBRRlbFRvQ2xUcmFuc2ZlcnNFcG9jaAUGaGVpZ2h0BQR1bml0CQACAQkArAICCQCsAgICJ0VMIHRvIENMIHRyYW5zZmVycyBhY3RpdmF0ZWQgb24gZXBvY2ggIwkApAMBBQZoZWlnaHQCFS4gVXBncmFkZSB5b3VyIGNsaWVudAEdcmVxdWlyZUVsVG9DbFRyYW5zZmVyc0VuYWJsZWQAAwkAZwIFBmhlaWdodAUUZWxUb0NsVHJhbnNmZXJzRXBvY2gFBHVuaXQJAAIBCQCsAgIJAKwCAgkArAICAi9FTCB0byBDTCB0cmFuc2ZlcnMgaGF2ZW4ndCBhY3RpdmF0ZWQgb24gZXBvY2ggIwkApAMBBQZoZWlnaHQCGi4gV2FpdCBmb3IgYWN0aXZhdGlvbiBvbiAjCQCkAwEFFGVsVG9DbFRyYW5zZmVyc0Vwb2NoABZzdGFraW5nQ29udHJhY3RBZGRyZXNzBAckbWF0Y2gwCQCdCAIFBHRoaXMFGXN0YWtpbmdDb250cmFjdEFkZHJlc3NLZXkDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQUBcwkArAICAiJpbnZhbGlkIHN0YWtpbmcgY29udHJhY3QgYWRkcmVzczogBQFzCQEHQWRkcmVzcwEJARFAZXh0ck5hdGl2ZSgxMDUyKQIFBHRoaXMFGXN0YWtpbmdDb250cmFjdEFkZHJlc3NLZXkBEWdlbmVyYXRpbmdCYWxhbmNlAQdhZGRyZXNzBAckbWF0Y2gwCQCdCAIFFnN0YWtpbmdDb250cmFjdEFkZHJlc3MJAKwCAgIEJXNfXwkApQgBBQdhZGRyZXNzAwkAAQIFByRtYXRjaDACBlN0cmluZwQDc3RyBQckbWF0Y2gwBAlwYXJhbUxpc3QJALUJAgUDc3RyAgJfXwQKcHJldkhlaWdodAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCXBhcmFtTGlzdAABBAtwcmV2QmFsYW5jZQkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCXBhcmFtTGlzdAACBApuZXh0SGVpZ2h0CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUJcGFyYW1MaXN0AAMEC25leHRCYWxhbmNlCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUJcGFyYW1MaXN0AAQDCQBnAgUGaGVpZ2h0BQpuZXh0SGVpZ2h0BQtuZXh0QmFsYW5jZQMJAGcCBQZoZWlnaHQFCnByZXZIZWlnaHQFC3ByZXZCYWxhbmNlAAAAAAEJY2hhaW5NZXRhAQdjaGFpbklkBAFzCQERQGV4dHJOYXRpdmUoMTA1OCkBCQEMY2hhaW5NZXRhS2V5AQUHY2hhaW5JZAQFaXRlbXMJALUJAgUBcwUDU0VQCQCUCgIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVpdGVtcwAACQCRAwIFBWl0ZW1zAAEAC21haW5DaGFpbklkCQELdmFsdWVPckVsc2UCCQCfCAEFDm1haW5DaGFpbklkS2V5AAAACyR0MDQ5MTE0OTc3CQEJY2hhaW5NZXRhAQULbWFpbkNoYWluSWQAD21haW5DaGFpbkhlaWdodAgFCyR0MDQ5MTE0OTc3Al8xABJtYWluQ2hhaW5MYXN0QmxvY2sIBQskdDA0OTExNDk3NwJfMgEJZXBvY2hNZXRhAQVlcG9jaAQHJG1hdGNoMAkAoggBCQEMZXBvY2hNZXRhS2V5AQUFZXBvY2gDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwBAlmcmFnbWVudHMJALUJAgUBcwUDU0VQCQCVCgMJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAJEDAgUJZnJhZ21lbnRzAAAJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQlmcmFnbWVudHMAAQkAkQMCBQlmcmFnbWVudHMAAgUEdW5pdAALJHQwNTIwODU2NzIEByRtYXRjaDAJAQllcG9jaE1ldGEBBQZoZWlnaHQDCQABAgUHJG1hdGNoMAIWKEFkZHJlc3MsIEludCwgU3RyaW5nKQQBbQUHJG1hdGNoMAUBbQQHJG1hdGNoMQkAoggBBRB0aGlzRXBvY2hEYXRhS2V5AwkAAQIFByRtYXRjaDECBlN0cmluZwQQcmF3VGhpc0Vwb2NoRGF0YQUHJG1hdGNoMQQNdGhpc0Vwb2NoRGF0YQkAtQkCBRByYXdUaGlzRXBvY2hEYXRhBQNTRVAECXRoaXNFcG9jaAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFDXRoaXNFcG9jaERhdGEAAAkAlQoDAwkAAAIFCXRoaXNFcG9jaAUGaGVpZ2h0CQERQGV4dHJOYXRpdmUoMTA2MikBCQCRAwIFDXRoaXNFcG9jaERhdGEAAQUEdW5pdAAAAgAJAJUKAwUEdW5pdAAAAgAADnRoaXNFcG9jaE1pbmVyCAULJHQwNTIwODU2NzICXzEADHRoaXNFcG9jaFJlZggFCyR0MDUyMDg1NjcyAl8yABJ0aGlzRXBvY2hMYXN0QmxvY2sIBQskdDA1MjA4NTY3MgJfMwAMYWxsTWluZXJzU3RyCQELdmFsdWVPckVsc2UCCQCiCAEFDGFsbE1pbmVyc0tleQIAAAlhbGxNaW5lcnMEByRtYXRjaDAFDGFsbE1pbmVyc1N0cgMJAAACAgAFByRtYXRjaDAFA25pbAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEA3JhdwUHJG1hdGNoMAkAvAkCBQNyYXcFA1NFUAkAAgECC01hdGNoIGVycm9yAQlibG9ja01ldGEBB2Jsb2NrSWQEBG1ldGEJARFAZXh0ck5hdGl2ZSgxMDU3KQEJAKwCAgUKYmxvY2tNZXRhSwUHYmxvY2tJZAQLYmxvY2tIZWlnaHQJALEJAQUEbWV0YQQKYmxvY2tFcG9jaAkAsgkCBQRtZXRhAAgEC2Jsb2NrUGFyZW50CQDJAQIJAMoBAgUEbWV0YQAQBQ9CTE9DS19IQVNIX1NJWkUEDmJsb2NrR2VuZXJhdG9yCQDJAQIJAMoBAgUEbWV0YQkAZAIAEAUPQkxPQ0tfSEFTSF9TSVpFBQxBRERSRVNTX1NJWkUDCQBmAgUUZWxUb0NsVHJhbnNmZXJzRXBvY2gFCmJsb2NrRXBvY2gJAJgKBgULYmxvY2tIZWlnaHQFCmJsb2NrRXBvY2gFC2Jsb2NrUGFyZW50BQ5ibG9ja0dlbmVyYXRvcgAAAQAEB2NoYWluSWQJALEJAQkAygECBQRtZXRhCQBkAgkAZAIAEAUPQkxPQ0tfSEFTSF9TSVpFBQxBRERSRVNTX1NJWkUEF2VsVG9DbFRyYW5zZmVyc1Jvb3RIYXNoCQDKAQIFBG1ldGEJAGQCCQBkAgAYBQ9CTE9DS19IQVNIX1NJWkUFDEFERFJFU1NfU0laRQkAmAoGBQtibG9ja0hlaWdodAUKYmxvY2tFcG9jaAULYmxvY2tQYXJlbnQFDmJsb2NrR2VuZXJhdG9yBQdjaGFpbklkBRdlbFRvQ2xUcmFuc2ZlcnNSb290SGFzaAEQbWtCbG9ja01ldGFFbnRyeQYMYmxvY2tIYXNoSGV4C2Jsb2NrSGVpZ2h0DmJsb2NrUGFyZW50SGV4DmJsb2NrR2VuZXJhdG9yB2NoYWluSWQaZWxUb0NsVHJhbnNmZXJzUm9vdEhhc2hIZXgED2Jsb2NrRXBvY2hCeXRlcwkAmgMBBQZoZWlnaHQEDmJsb2NrTWV0YUJ5dGVzCQDLAQIJAMsBAgkAywECCQDLAQIJAMsBAgkAmgMBBQtibG9ja0hlaWdodAUPYmxvY2tFcG9jaEJ5dGVzCQDdBAEFDmJsb2NrUGFyZW50SGV4CAUOYmxvY2tHZW5lcmF0b3IFYnl0ZXMJAJoDAQUHY2hhaW5JZAkA3QQBBRplbFRvQ2xUcmFuc2ZlcnNSb290SGFzaEhleAkBC0JpbmFyeUVudHJ5AgkArAICBQpibG9ja01ldGFLBQxibG9ja0hhc2hIZXgFDmJsb2NrTWV0YUJ5dGVzAQxsYXN0SGVpZ2h0QnkCBW1pbmVyB2NoYWluSWQEByRtYXRjaDAJAJ8IAQkBEmNoYWluTGFzdEhlaWdodEtleQIFB2NoYWluSWQFBW1pbmVyAwkAAQIFByRtYXRjaDACA0ludAQBaAUHJG1hdGNoMAUBaAQJYmxvY2tIYXNoCQERQGV4dHJOYXRpdmUoMTA1OCkBCQCsAgIJAKwCAgkArAICAgVjaGFpbgkApAMBBQdjaGFpbklkAgtMYXN0TWluZWRCeQkApQgBBQVtaW5lcggJAQlibG9ja01ldGEBBQlibG9ja0hhc2gCXzEACyR0MDczMjA4Mjg2BAloaXRTb3VyY2UEByRtYXRjaDAIBQlsYXN0QmxvY2sDdnJmAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEA3ZyZgUHJG1hdGNoMAUDdnJmCAUJbGFzdEJsb2NrE2dlbmVyYXRpb25TaWduYXR1cmUKAQxwcm9jZXNzTWluZXICBHByZXYFbWluZXIECyR0MDc2MTg3NjgxBQRwcmV2BAlwcmV2RGVsYXkIBQskdDA3NjE4NzY4MQJfMQQJcHJldk1pbmVyCAULJHQwNzYxODc2ODECXzIEEHByZXZUb3RhbEJhbGFuY2UIBQskdDA3NjE4NzY4MQJfMwQKcHJldk1pbmVycwgFCyR0MDc2MTg3NjgxAl80BAxtaW5lckFkZHJlc3MJARFAZXh0ck5hdGl2ZSgxMDYyKQEFBW1pbmVyBA93YXZlc0dlbkJhbGFuY2UICQDvBwEFDG1pbmVyQWRkcmVzcwpnZW5lcmF0aW5nBAxtaW5lckJhbGFuY2UJARFnZW5lcmF0aW5nQmFsYW5jZQEFDG1pbmVyQWRkcmVzcwMDCQBmAgULTUlOX0JBTEFOQ0UFD3dhdmVzR2VuQmFsYW5jZQYJAGcCAAAFDG1pbmVyQmFsYW5jZQUEcHJldgQJbmV4dERlbGF5CQCFBwIFDG1pbmVyQWRkcmVzcwUMbWluZXJCYWxhbmNlAwkAZgIFCXByZXZEZWxheQUJbmV4dERlbGF5CQCWCgQFCW5leHREZWxheQUFbWluZXIJAGQCBRBwcmV2VG90YWxCYWxhbmNlBQxtaW5lckJhbGFuY2UJAM0IAgUKcHJldk1pbmVycwUFbWluZXIJAJYKBAUJcHJldkRlbGF5BQlwcmV2TWluZXIJAGQCBRBwcmV2VG90YWxCYWxhbmNlBQxtaW5lckJhbGFuY2UJAM0IAgUKcHJldk1pbmVycwUFbWluZXIKAAIkbAUJYWxsTWluZXJzCgACJHMJAJADAQUCJGwKAAUkYWNjMAkAlgoEBQdJTlRfTUFYAgAAAAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQxwcm9jZXNzTWluZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDUwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgANY29tcHV0ZWREZWxheQgFCyR0MDczMjA4Mjg2Al8xABFjb21wdXRlZEdlbmVyYXRvcggFCyR0MDczMjA4Mjg2Al8yABRjb21wdXRlZFRvdGFsQmFsYW5jZQgFCyR0MDczMjA4Mjg2Al8zAA5maWx0ZXJlZE1pbmVycwgFCyR0MDczMjA4Mjg2Al80ARNnZXRDaGFpbkxhc3RCbG9ja0lkAQdjaGFpbklkCAkBCWNoYWluTWV0YQEFB2NoYWluSWQCXzIACyR0MDgzNTI4NDg3CQEJYmxvY2tNZXRhAQUSbWFpbkNoYWluTGFzdEJsb2NrAAxtY2xiSWdub3JlZDEIBQskdDA4MzUyODQ4NwJfMQAObWFpbkNoYWluRXBvY2gIBQskdDA4MzUyODQ4NwJfMgATbWFpbkNoYWluUGFyZW50SGFzaAgFCyR0MDgzNTI4NDg3Al8zABJtYWluQ2hhaW5HZW5lcmF0b3IIBQskdDA4MzUyODQ4NwJfNAAMbWNsYklnbm9yZWQyCAULJHQwODM1Mjg0ODcCXzUADG1jbGJJZ25vcmVkMwgFCyR0MDgzNTI4NDg3Al82ARtjYWxjdWxhdGVGaW5hbGl6ZWRCbG9ja0hhc2gDCGN1ck1pbmVyDGN1clByZXZFcG9jaBBjdXJMYXN0QmxvY2tIYXNoBAtvZmZzZXRzXzEwMAkAvAkCAmQ6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6AgAEC2hhbGZCYWxhbmNlCQBpAgUUY29tcHV0ZWRUb3RhbEJhbGFuY2UAAgoBBHN0ZXACBHByZXYEbmV4dAQLJHQwODg1Mzg5MTcFBHByZXYECXRoaXNFcG9jaAgFCyR0MDg4NTM4OTE3Al8xBAx0b3RhbEJhbGFuY2UIBQskdDA4ODUzODkxNwJfMgQObWF5YmVTYWZlRXBvY2gIBQskdDA4ODUzODkxNwJfMwQKcHJldk1pbmVycwgFCyR0MDg4NTM4OTE3Al80BAckbWF0Y2gwBQ5tYXliZVNhZmVFcG9jaAMJAAECBQckbWF0Y2gwAgRVbml0BAskdDA4OTc1OTE0MQMJAAACBQl0aGlzRXBvY2gFBmhlaWdodAkAlQoDBQhjdXJNaW5lcgUMY3VyUHJldkVwb2NoBRBjdXJMYXN0QmxvY2tIYXNoCQEFdmFsdWUBCQEJZXBvY2hNZXRhAQUJdGhpc0Vwb2NoBAVtaW5lcggFCyR0MDg5NzU5MTQxAl8xBAlwcmV2RXBvY2gIBQskdDA4OTc1OTE0MQJfMgQNbGFzdEJsb2NrSGFzaAgFCyR0MDg5NzU5MTQxAl8zAwkAAAIFCXByZXZFcG9jaAAACQCWCgQFCXRoaXNFcG9jaAUMdG90YWxCYWxhbmNlBQ1sYXN0QmxvY2tIYXNoBQlhbGxNaW5lcnMECyR0MDkyNjY5NDY4AwkBD2NvbnRhaW5zRWxlbWVudAIFCnByZXZNaW5lcnMFBW1pbmVyCQCUCgIFDHRvdGFsQmFsYW5jZQUKcHJldk1pbmVycwkAlAoCCQBkAgUMdG90YWxCYWxhbmNlCQERZ2VuZXJhdGluZ0JhbGFuY2UBBQVtaW5lcgkAzAgCBQVtaW5lcgUKcHJldk1pbmVycwQPbmV3VG90YWxCYWxhbmNlCAULJHQwOTI2Njk0NjgCXzEECW5ld01pbmVycwgFCyR0MDkyNjY5NDY4Al8yAwkAZgIFD25ld1RvdGFsQmFsYW5jZQULaGFsZkJhbGFuY2UJAJYKBAUJdGhpc0Vwb2NoBQ9uZXdUb3RhbEJhbGFuY2UFDWxhc3RCbG9ja0hhc2gFCWFsbE1pbmVycwkAlgoEBQlwcmV2RXBvY2gFD25ld1RvdGFsQmFsYW5jZQUEdW5pdAUJbmV3TWluZXJzBQRwcmV2BAskdDA5NzAxOTgzNAoAAiRsCQDOCAIFC29mZnNldHNfMTAwBQtvZmZzZXRzXzEwMAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAJAJYKBAUGaGVpZ2h0AAAFBHVuaXQFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEEc3RlcAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIVTGlzdCBzaXplIGV4Y2VlZHMgMjAwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgA/AEAAQQBCAEMARABFAEYARwBIAEkASgBLAEwATQBOAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAF4AXwBgAGEAYgBjAGQAZQBmAGcAaABpAGoAawBsAG0AbgBvAHAAcQByAHMAdAB1AHYAdwB4AHkAegB7AHwAfQB+AH8AgAEAgQEAggEAgwEAhAEAhQEAhgEAhwEAiAEAiQEAigEAiwEAjAEAjQEAjgEAjwEAkAEAkQEAkgEAkwEAlAEAlQEAlgEAlwEAmAEAmQEAmgEAmwEAnAEAnQEAngEAnwEAoAEAoQEAogEAowEApAEApQEApgEApwEAqAEAqQEAqgEAqwEArAEArQEArgEArwEAsAEAsQEAsgEAswEAtAEAtQEAtgEAtwEAuAEAuQEAugEAuwEAvAEAvQEAvgEAvwEAwAEAwQEAwgEAwwEAxAEAxQEAxgEAxwEAyAEEDWZhbGxiYWNrRXBvY2gIBQskdDA5NzAxOTgzNAJfMQQMdG90YWxCYWxhbmNlCAULJHQwOTcwMTk4MzQCXzIEFWZpbmFsaXplZEJsb2NrSGFzaE9wdAgFCyR0MDk3MDE5ODM0Al8zBAZtaW5lcnMIBQskdDA5NzAxOTgzNAJfNAQHJG1hdGNoMAUVZmluYWxpemVkQmxvY2tIYXNoT3B0AwkAAQIFByRtYXRjaDACBlN0cmluZwQSZmluYWxpemVkQmxvY2tIYXNoBQckbWF0Y2gwBRJmaW5hbGl6ZWRCbG9ja0hhc2gICQEFdmFsdWUBCQEJZXBvY2hNZXRhAQUNZmFsbGJhY2tFcG9jaAJfMwERc3VwcG9ydGluZ0JhbGFuY2UBB2NoYWluSWQKAQphZGRCYWxhbmNlAgNhY2MMZ2VuZXJhdG9yU3RyBA0kdDAxMDEwNDEwMTQwBQNhY2MEDHRvdGFsQmFsYW5jZQgFDSR0MDEwMTA0MTAxNDACXzEECmdlbmVyYXRvcnMIBQ0kdDAxMDEwNDEwMTQwAl8yBAlnZW5lcmF0b3IJARFAZXh0ck5hdGl2ZSgxMDYyKQEFDGdlbmVyYXRvclN0cgMJAQ9jb250YWluc0VsZW1lbnQCBQpnZW5lcmF0b3JzBQlnZW5lcmF0b3IFA2FjYwQHYmFsYW5jZQkBEWdlbmVyYXRpbmdCYWxhbmNlAQUJZ2VuZXJhdG9yCQCUCgIJAGQCBQx0b3RhbEJhbGFuY2UFB2JhbGFuY2UJAM0IAgUKZ2VuZXJhdG9ycwUJZ2VuZXJhdG9yBA1hbGxHZW5lcmF0b3JzCQC8CQIJARFAZXh0ck5hdGl2ZSgxMDU4KQEJAQ1zdXBwb3J0ZXJzS2V5AQUHY2hhaW5JZAUDU0VQBA0kdDAxMDQ2MjEwNTI3CgACJGwFDWFsbEdlbmVyYXRvcnMKAAIkcwkAkAMBBQIkbAoABSRhY2MwCQCUCgIAAAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQphZGRCYWxhbmNlAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhVMaXN0IHNpemUgZXhjZWVkcyAxMDAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AD8AQABBAEIAQwBEAEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgBfAGAAYQBiAGMAZAQHYmFsYW5jZQgFDSR0MDEwNDYyMTA1MjcCXzEEAl9nCAUNJHQwMTA0NjIxMDUyNwJfMgUHYmFsYW5jZQEPaXNDb250cmFjdFNldHVwAAkBCWlzRGVmaW5lZAEJAJ8IAQUObWluZXJSZXdhcmRLZXkBEWVuc3VyZU1pbmluZ0Vwb2NoAQlnZW5lcmF0b3IDCQECIT0CCQClCAEFCWdlbmVyYXRvcgURY29tcHV0ZWRHZW5lcmF0b3IJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJANgEAQgFCWdlbmVyYXRvcgVieXRlcwIbIGlzIG5vdCBhbGxvd2VkIHRvIG1pbmUgaW4gCQCkAwEFBmhlaWdodAIRIGVwb2NoLiBFeHBlY3RlZCAFEWNvbXB1dGVkR2VuZXJhdG9yBQR1bml0ARJpc1JlZmVyZW5jZUNvcnJlY3QCCXJlZmVyZW5jZQlsYXN0QmxvY2sDCQAAAgUJcmVmZXJlbmNlBQlsYXN0QmxvY2sFBHVuaXQJAAIBCQCsAgIJAKwCAgkArAICAjBFeHBlY3RlZCBhIHJlZmVyZW5jZSB0byB0aGUgY2hhaW4gbGFzdCBibG9jazogMHgFCWxhc3RCbG9jawIJLiBHb3Q6IDB4BQlyZWZlcmVuY2UBD2NoYWluSXNJbmFjdGl2ZQEHY2hhaW5JZAQMZmlyc3RCbG9ja0lkCQERQGV4dHJOYXRpdmUoMTA1OCkBCQEUY2hhaW5GaXJzdEJsb2NrSWRLZXkBBQdjaGFpbklkBBRmaXJzdFZhbGlkQWx0Q2hhaW5JZAkBC3ZhbHVlT3JFbHNlAgkAnwgBBRdmaXJzdFZhbGlkQWx0Q2hhaW5JZEtleQAAAwkAZgIFFGZpcnN0VmFsaWRBbHRDaGFpbklkBQdjaGFpbklkBgkAZgIICQEJYmxvY2tNZXRhAQkBEUBleHRyTmF0aXZlKDEwNTgpAQURZmluYWxpemVkQmxvY2tLZXkCXzEICQEJYmxvY2tNZXRhAQUMZmlyc3RCbG9ja0lkAl8xAQxtaW5lckNoYWluSWQBBW1pbmVyCQELdmFsdWVPckVsc2UCCQCfCAEJAQ9taW5lckNoYWluSWRLZXkBBQVtaW5lcgkAnwgBCQCsAgICCWNoYWluSWRPZgkApQgBBQVtaW5lcgEdZW5zdXJlRXhwZWN0ZWRPckluYWN0aXZlQ2hhaW4DCWdlbmVyYXRvcg9leHBlY3RlZENoYWluSWQQY2hlY2tIZWlnaHRCbG9jawQPaGVpZ2h0SXNDb3JyZWN0BAckbWF0Y2gwBRBjaGVja0hlaWdodEJsb2NrAwkAAQIFByRtYXRjaDACBlN0cmluZwQJYmxvY2tIYXNoBQckbWF0Y2gwBBRsYXN0TWluZWRCbG9ja0hlaWdodAkBDGxhc3RIZWlnaHRCeQIFCWdlbmVyYXRvcgULbWFpbkNoYWluSWQJAGYCCQBkAggJAQlibG9ja01ldGEBBQlibG9ja0hhc2gCXzEAAQUUbGFzdE1pbmVkQmxvY2tIZWlnaHQGBAckbWF0Y2gwCQEMbWluZXJDaGFpbklkAQUJZ2VuZXJhdG9yAwkAAQIFByRtYXRjaDACA0ludAQJY3VycmVudElkBQckbWF0Y2gwAwMJAAACBQljdXJyZW50SWQFD2V4cGVjdGVkQ2hhaW5JZAYDCQEPY2hhaW5Jc0luYWN0aXZlAQUJY3VycmVudElkBQ9oZWlnaHRJc0NvcnJlY3QHBQR1bml0CQACAQkArAICAhxtaW5lciBpcyBtaW5pbmcgb3RoZXIgY2hhaW4gCQCkAwEFCWN1cnJlbnRJZAUEdW5pdAESZW5zdXJlQ29ycmVjdEVwb2NoAQVlcG9jaAMJAAACBQVlcG9jaAUGaGVpZ2h0BQR1bml0CQACAQkArAICCQCsAgIJAKwCAgIaRXhwZWN0ZWQgYmxvY2sgZnJvbSBlcG9jaCAJAKQDAQUGaGVpZ2h0AgYuIEdvdCAJAKQDAQUFZXBvY2gBDGFkZFN1cHBvcnRlcgIHY2hhaW5JZAlnZW5lcmF0b3IEDXN1cHBvcnRlcnNTdHIJARFAZXh0ck5hdGl2ZSgxMDU4KQEJAQ1zdXBwb3J0ZXJzS2V5AQUHY2hhaW5JZAQKc3VwcG9ydGVycwkAvAkCBQ1zdXBwb3J0ZXJzU3RyBQNTRVADCQEPY29udGFpbnNFbGVtZW50AgUKc3VwcG9ydGVycwkApQgBBQlnZW5lcmF0b3IFA25pbAkAzAgCCQELU3RyaW5nRW50cnkCCQENc3VwcG9ydGVyc0tleQEFB2NoYWluSWQJAKwCAgkArAICBQ1zdXBwb3J0ZXJzU3RyBQNTRVAJAKUIAQUJZ2VuZXJhdG9yBQNuaWwBCXNldE9yRmFpbAIFZmxhZ3MFaW5kZXgDCQBmAgAABQVpbmRleAkAAgEJAKwCAgIiQ2FuJ3Qgd2l0aGRyYXcgYXQgbmVnYXRpdmUgaW5kZXg6IAkApAMBBQVpbmRleAQJZmxhZ3NTaXplCQCxAgEFBWZsYWdzAwkAZwIFBWluZGV4BQlmbGFnc1NpemUECWFkZFplcm9lcwkAZQIFBWluZGV4BQlmbGFnc1NpemUDCQBmAgUJYWRkWmVyb2VzCQCxAgEFCXplcm9lc1N0cgkAAgEJAKwCAgkArAICAgpDYW4ndCBhZGQgCQCkAwEFCWFkZFplcm9lcwIlIGVtcHR5IGZsYWdzLiBDb250YWN0IHdpdGggZGV2ZWxvcGVycwkArAICCQCsAgIFBWZsYWdzCQCvAgIFCXplcm9lc1N0cgUJYWRkWmVyb2VzAgExBAR0YWlsCQCwAgIFBWZsYWdzBQVpbmRleAQHYXRJbmRleAkArwICBQR0YWlsAAEDCQAAAgUHYXRJbmRleAIBMAkArAICCQCsAgIJAK8CAgUFZmxhZ3MFBWluZGV4AgExCQCwAgIFBHRhaWwAAQkAAgEJAKwCAgkArAICAgpUcmFuc2ZlciAjCQCkAwEFBWluZGV4AhcgaGFzIGJlZW4gYWxyZWFkeSB0YWtlbgERdmFsaWRhdGVCbG9ja0hhc2gBBmhleFN0cgQMZGVjb2RlZEJ5dGVzCQDdBAEFBmhleFN0cgMJAQIhPQIJAMgBAQUMZGVjb2RlZEJ5dGVzACAJAAIBAhdpbnZhbGlkIGJsb2NrIGlkIGxlbmd0aAUGaGV4U3RyAR1nZXRVcGRhdGVGaW5hbGl6ZWRCbG9ja0FjdGlvbgMGY2FsbGVyD25ld0Jsb2NrSGFzaEhleAlwcmV2RXBvY2gEF2N1ckZpbmFsaXplZEJsb2NrSGVpZ2h0CAkBCWJsb2NrTWV0YQEJARFAZXh0ck5hdGl2ZSgxMDU4KQEFEWZpbmFsaXplZEJsb2NrS2V5Al8xBBVuZXdGaW5hbGl6ZWRCbG9ja0hhc2gJARtjYWxjdWxhdGVGaW5hbGl6ZWRCbG9ja0hhc2gDBQZjYWxsZXIFCXByZXZFcG9jaAUPbmV3QmxvY2tIYXNoSGV4AwMJAAACBRVuZXdGaW5hbGl6ZWRCbG9ja0hhc2gFD25ld0Jsb2NrSGFzaEhleAYJAGYCCAkBCWJsb2NrTWV0YQEFFW5ld0ZpbmFsaXplZEJsb2NrSGFzaAJfMQUXY3VyRmluYWxpemVkQmxvY2tIZWlnaHQJAMwIAgkBC1N0cmluZ0VudHJ5AgURZmluYWxpemVkQmxvY2tLZXkFFW5ld0ZpbmFsaXplZEJsb2NrSGFzaAUDbmlsBQNuaWwNAWkBC2FwcGVuZEJsb2NrAgxibG9ja0hhc2hIZXgMcmVmZXJlbmNlSGV4BAxjaGVja1ZlcnNpb24JAR5yZXF1aXJlRWxUb0NsVHJhbnNmZXJzRGlzYWJsZWQAAwkAAAIFDGNoZWNrVmVyc2lvbgUMY2hlY2tWZXJzaW9uAwkBAiE9AgUOdGhpc0Vwb2NoTWluZXIIBQFpDG9yaWdpbkNhbGxlcgQHJG1hdGNoMAUOdGhpc0Vwb2NoTWluZXIDCQABAgUHJG1hdGNoMAIHQWRkcmVzcwQKZXBvY2hNaW5lcgUHJG1hdGNoMAkAAgEJAKwCAgI5bm90IGFsbG93ZWQgdG8gZm9yZ2UgYmxvY2tzIGluIHRoaXMgZXBvY2gsIGV4cGVjdGVkIGZyb20gCQClCAEFCmVwb2NoTWluZXIJAAIBAkBub3QgYWxsb3dlZCB0byBmb3JnZSBibG9ja3MgaW4gdGhpcyBlcG9jaCwgZXBvY2ggbWluZXIgaXMgYWJzZW50BAdjaGFpbklkCQELdmFsdWVPckVsc2UCCQEMbWluZXJDaGFpbklkAQgFAWkMb3JpZ2luQ2FsbGVyBQttYWluQ2hhaW5JZAQNJHQwMTQ2NDQxNDY5NQkBCWNoYWluTWV0YQEFB2NoYWluSWQEC2NoYWluSGVpZ2h0CAUNJHQwMTQ2NDQxNDY5NQJfMQQLbGFzdEJsb2NrSWQIBQ0kdDAxNDY0NDE0Njk1Al8yBA5jaGVja1JlZmVyZW5jZQkBEmlzUmVmZXJlbmNlQ29ycmVjdAIFDHJlZmVyZW5jZUhleAULbGFzdEJsb2NrSWQDCQAAAgUOY2hlY2tSZWZlcmVuY2UFDmNoZWNrUmVmZXJlbmNlBA5uZXdDaGFpbkhlaWdodAkAZAIFC2NoYWluSGVpZ2h0AAEEDG5ld0Jsb2NrTWV0YQkAywECCQDLAQIJAMsBAgkAmgMBBQ5uZXdDaGFpbkhlaWdodAkAmgMBBQZoZWlnaHQJAN0EAQULbGFzdEJsb2NrSWQICAUBaQxvcmlnaW5DYWxsZXIFYnl0ZXMEDmNoZWNrQmxvY2tIYXNoCQERdmFsaWRhdGVCbG9ja0hhc2gBBQxibG9ja0hhc2hIZXgDCQAAAgUOY2hlY2tCbG9ja0hhc2gFDmNoZWNrQmxvY2tIYXNoCQDMCAIJAQtCaW5hcnlFbnRyeQIJAKwCAgUKYmxvY2tNZXRhSwUMYmxvY2tIYXNoSGV4BQxuZXdCbG9ja01ldGEJAMwIAgkBDEludGVnZXJFbnRyeQIJARJjaGFpbkxhc3RIZWlnaHRLZXkCBQdjaGFpbklkCAUBaQxvcmlnaW5DYWxsZXIFDm5ld0NoYWluSGVpZ2h0CQDMCAIJAQtTdHJpbmdFbnRyeQIJAQxjaGFpbk1ldGFLZXkBBQdjaGFpbklkCQCsAgIJAKwCAgkApAMBBQ5uZXdDaGFpbkhlaWdodAUDU0VQBQxibG9ja0hhc2hIZXgJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDGVwb2NoTWV0YUtleQEFBmhlaWdodAkArAICCQCsAgIJAKwCAgkArAICCQClCAEJAQV2YWx1ZQEFDnRoaXNFcG9jaE1pbmVyBQNTRVAJAKQDAQUMdGhpc0Vwb2NoUmVmBQNTRVAFDGJsb2NrSGFzaEhleAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmFwcGVuZEJsb2NrX3YyAwxibG9ja0hhc2hIZXgMcmVmZXJlbmNlSGV4GmVsVG9DbFRyYW5zZmVyc1Jvb3RIYXNoSGV4BAxjaGVja1ZlcnNpb24JAR1yZXF1aXJlRWxUb0NsVHJhbnNmZXJzRW5hYmxlZAADCQAAAgUMY2hlY2tWZXJzaW9uBQxjaGVja1ZlcnNpb24DCQECIT0CBQ50aGlzRXBvY2hNaW5lcggFAWkMb3JpZ2luQ2FsbGVyBAckbWF0Y2gwBQ50aGlzRXBvY2hNaW5lcgMJAAECBQckbWF0Y2gwAgdBZGRyZXNzBAplcG9jaE1pbmVyBQckbWF0Y2gwCQACAQkArAICAjlub3QgYWxsb3dlZCB0byBmb3JnZSBibG9ja3MgaW4gdGhpcyBlcG9jaCwgZXhwZWN0ZWQgZnJvbSAJAKUIAQUKZXBvY2hNaW5lcgkAAgECQG5vdCBhbGxvd2VkIHRvIGZvcmdlIGJsb2NrcyBpbiB0aGlzIGVwb2NoLCBlcG9jaCBtaW5lciBpcyBhYnNlbnQEB2NoYWluSWQJAQt2YWx1ZU9yRWxzZQIJAQxtaW5lckNoYWluSWQBCAUBaQxvcmlnaW5DYWxsZXIFC21haW5DaGFpbklkBA0kdDAxNTk2OTE2MDIwCQEJY2hhaW5NZXRhAQUHY2hhaW5JZAQLY2hhaW5IZWlnaHQIBQ0kdDAxNTk2OTE2MDIwAl8xBAtsYXN0QmxvY2tJZAgFDSR0MDE1OTY5MTYwMjACXzIEDmNoZWNrUmVmZXJlbmNlCQESaXNSZWZlcmVuY2VDb3JyZWN0AgUMcmVmZXJlbmNlSGV4BQtsYXN0QmxvY2tJZAMJAAACBQ5jaGVja1JlZmVyZW5jZQUOY2hlY2tSZWZlcmVuY2UEDm5ld0NoYWluSGVpZ2h0CQBkAgULY2hhaW5IZWlnaHQAAQQOY2hlY2tCbG9ja0hhc2gJARF2YWxpZGF0ZUJsb2NrSGFzaAEFDGJsb2NrSGFzaEhleAMJAAACBQ5jaGVja0Jsb2NrSGFzaAUOY2hlY2tCbG9ja0hhc2gJAMwIAgkBEG1rQmxvY2tNZXRhRW50cnkGBQxibG9ja0hhc2hIZXgFDm5ld0NoYWluSGVpZ2h0BQtsYXN0QmxvY2tJZAgFAWkMb3JpZ2luQ2FsbGVyBQdjaGFpbklkBRplbFRvQ2xUcmFuc2ZlcnNSb290SGFzaEhleAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEmNoYWluTGFzdEhlaWdodEtleQIFB2NoYWluSWQIBQFpDG9yaWdpbkNhbGxlcgUObmV3Q2hhaW5IZWlnaHQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDGNoYWluTWV0YUtleQEFB2NoYWluSWQJAKwCAgkArAICCQCkAwEFDm5ld0NoYWluSGVpZ2h0BQNTRVAFDGJsb2NrSGFzaEhleAkAzAgCCQELU3RyaW5nRW50cnkCCQEMZXBvY2hNZXRhS2V5AQUGaGVpZ2h0CQCsAgIJAKwCAgkArAICCQCsAgIJAKUIAQkBBXZhbHVlAQUOdGhpc0Vwb2NoTWluZXIFA1NFUAkApAMBBQx0aGlzRXBvY2hSZWYFA1NFUAUMYmxvY2tIYXNoSGV4BQNuaWwJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEPZXh0ZW5kTWFpbkNoYWluAwxibG9ja0hhc2hIZXgMcmVmZXJlbmNlSGV4BWVwb2NoBAxjaGVja1ZlcnNpb24JAR5yZXF1aXJlRWxUb0NsVHJhbnNmZXJzRGlzYWJsZWQAAwkAAAIFDGNoZWNrVmVyc2lvbgUMY2hlY2tWZXJzaW9uBA5jaGVja0Jsb2NrSGFzaAkBEXZhbGlkYXRlQmxvY2tIYXNoAQUMYmxvY2tIYXNoSGV4AwkAAAIFDmNoZWNrQmxvY2tIYXNoBQ5jaGVja0Jsb2NrSGFzaAQKY2hlY2tFcG9jaAkBEmVuc3VyZUNvcnJlY3RFcG9jaAEFBWVwb2NoAwkAAAIFCmNoZWNrRXBvY2gFCmNoZWNrRXBvY2gEDmNoZWNrR2VuZXJhdG9yCQERZW5zdXJlTWluaW5nRXBvY2gBCAUBaQxvcmlnaW5DYWxsZXIDCQAAAgUOY2hlY2tHZW5lcmF0b3IFDmNoZWNrR2VuZXJhdG9yBApjaGVja0NoYWluCQEdZW5zdXJlRXhwZWN0ZWRPckluYWN0aXZlQ2hhaW4DCAUBaQxvcmlnaW5DYWxsZXIFC21haW5DaGFpbklkBQR1bml0AwkAAAIFCmNoZWNrQ2hhaW4FCmNoZWNrQ2hhaW4EDmNoZWNrUmVmZXJlbmNlCQESaXNSZWZlcmVuY2VDb3JyZWN0AgUMcmVmZXJlbmNlSGV4BRJtYWluQ2hhaW5MYXN0QmxvY2sDCQAAAgUOY2hlY2tSZWZlcmVuY2UFDmNoZWNrUmVmZXJlbmNlBA10aGlzRXBvY2hNZXRhBAckbWF0Y2gwCQEJZXBvY2hNZXRhAQUGaGVpZ2h0AwkAAQIFByRtYXRjaDACBFVuaXQJAQtTdHJpbmdFbnRyeQIJAQxlcG9jaE1ldGFLZXkBBQZoZWlnaHQJAKwCAgkArAICCQCsAgIJAKwCAgkApQgBCAUBaQxvcmlnaW5DYWxsZXIFA1NFUAkApAMBBQ5tYWluQ2hhaW5FcG9jaAUDU0VQBQxibG9ja0hhc2hIZXgEBW90aGVyBQckbWF0Y2gwCQACAQIVRXBvY2ggYWxyZWFkeSBzdGFydGVkBBR1cGRhdGVGaW5hbGl6ZWRCbG9jawkBHWdldFVwZGF0ZUZpbmFsaXplZEJsb2NrQWN0aW9uAwgFAWkMb3JpZ2luQ2FsbGVyBQxibG9ja0hhc2hIZXgFDm1haW5DaGFpbkVwb2NoBA5uZXdDaGFpbkhlaWdodAkAZAIFD21haW5DaGFpbkhlaWdodAABBAxuZXdCbG9ja01ldGEJAMsBAgkAywECCQDLAQIJAJoDAQUObmV3Q2hhaW5IZWlnaHQJAJoDAQUGaGVpZ2h0CQDdBAEFEm1haW5DaGFpbkxhc3RCbG9jawgIBQFpDG9yaWdpbkNhbGxlcgVieXRlcwkAzggCCQDMCAIJAQtCaW5hcnlFbnRyeQIJAKwCAgUKYmxvY2tNZXRhSwUMYmxvY2tIYXNoSGV4BQxuZXdCbG9ja01ldGEJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDGNoYWluTWV0YUtleQEFC21haW5DaGFpbklkCQCsAgIJAKwCAgkApAMBBQ5uZXdDaGFpbkhlaWdodAUDU0VQBQxibG9ja0hhc2hIZXgJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ9taW5lckNoYWluSWRLZXkBCAUBaQxvcmlnaW5DYWxsZXIFC21haW5DaGFpbklkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQESY2hhaW5MYXN0SGVpZ2h0S2V5AgULbWFpbkNoYWluSWQIBQFpDG9yaWdpbkNhbGxlcgUObmV3Q2hhaW5IZWlnaHQJAMwIAgUNdGhpc0Vwb2NoTWV0YQUDbmlsBRR1cGRhdGVGaW5hbGl6ZWRCbG9jawkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARJleHRlbmRNYWluQ2hhaW5fdjIEDGJsb2NrSGFzaEhleAxyZWZlcmVuY2VIZXgFZXBvY2gaZWxUb0NsVHJhbnNmZXJzUm9vdEhhc2hIZXgEDGNoZWNrVmVyc2lvbgkBHXJlcXVpcmVFbFRvQ2xUcmFuc2ZlcnNFbmFibGVkAAMJAAACBQxjaGVja1ZlcnNpb24FDGNoZWNrVmVyc2lvbgQOY2hlY2tCbG9ja0hhc2gJARF2YWxpZGF0ZUJsb2NrSGFzaAEFDGJsb2NrSGFzaEhleAMJAAACBQ5jaGVja0Jsb2NrSGFzaAUOY2hlY2tCbG9ja0hhc2gECmNoZWNrRXBvY2gJARJlbnN1cmVDb3JyZWN0RXBvY2gBBQVlcG9jaAMJAAACBQpjaGVja0Vwb2NoBQpjaGVja0Vwb2NoBA5jaGVja0dlbmVyYXRvcgkBEWVuc3VyZU1pbmluZ0Vwb2NoAQgFAWkMb3JpZ2luQ2FsbGVyAwkAAAIFDmNoZWNrR2VuZXJhdG9yBQ5jaGVja0dlbmVyYXRvcgQKY2hlY2tDaGFpbgkBHWVuc3VyZUV4cGVjdGVkT3JJbmFjdGl2ZUNoYWluAwgFAWkMb3JpZ2luQ2FsbGVyBQttYWluQ2hhaW5JZAUEdW5pdAMJAAACBQpjaGVja0NoYWluBQpjaGVja0NoYWluBA5jaGVja1JlZmVyZW5jZQkBEmlzUmVmZXJlbmNlQ29ycmVjdAIFDHJlZmVyZW5jZUhleAUSbWFpbkNoYWluTGFzdEJsb2NrAwkAAAIFDmNoZWNrUmVmZXJlbmNlBQ5jaGVja1JlZmVyZW5jZQQNdGhpc0Vwb2NoTWV0YQQHJG1hdGNoMAkBCWVwb2NoTWV0YQEFBmhlaWdodAMJAAECBQckbWF0Y2gwAgRVbml0CQELU3RyaW5nRW50cnkCCQEMZXBvY2hNZXRhS2V5AQUGaGVpZ2h0CQCsAgIJAKwCAgkArAICCQCsAgIJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBQNTRVAJAKQDAQUObWFpbkNoYWluRXBvY2gFA1NFUAUMYmxvY2tIYXNoSGV4BAVvdGhlcgUHJG1hdGNoMAkAAgECFUVwb2NoIGFscmVhZHkgc3RhcnRlZAQUdXBkYXRlRmluYWxpemVkQmxvY2sJAR1nZXRVcGRhdGVGaW5hbGl6ZWRCbG9ja0FjdGlvbgMIBQFpDG9yaWdpbkNhbGxlcgUMYmxvY2tIYXNoSGV4BQ5tYWluQ2hhaW5FcG9jaAQObmV3Q2hhaW5IZWlnaHQJAGQCBQ9tYWluQ2hhaW5IZWlnaHQAAQkAzggCCQDMCAIJARBta0Jsb2NrTWV0YUVudHJ5BgUMYmxvY2tIYXNoSGV4BQ5uZXdDaGFpbkhlaWdodAUSbWFpbkNoYWluTGFzdEJsb2NrCAUBaQxvcmlnaW5DYWxsZXIFC21haW5DaGFpbklkBRplbFRvQ2xUcmFuc2ZlcnNSb290SGFzaEhleAkAzAgCCQELU3RyaW5nRW50cnkCCQEMY2hhaW5NZXRhS2V5AQULbWFpbkNoYWluSWQJAKwCAgkArAICCQCkAwEFDm5ld0NoYWluSGVpZ2h0BQNTRVAFDGJsb2NrSGFzaEhleAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBD21pbmVyQ2hhaW5JZEtleQEIBQFpDG9yaWdpbkNhbGxlcgULbWFpbkNoYWluSWQJAMwIAgkBDEludGVnZXJFbnRyeQIJARJjaGFpbkxhc3RIZWlnaHRLZXkCBQttYWluQ2hhaW5JZAgFAWkMb3JpZ2luQ2FsbGVyBQ5uZXdDaGFpbkhlaWdodAkAzAgCBQ10aGlzRXBvY2hNZXRhBQNuaWwFFHVwZGF0ZUZpbmFsaXplZEJsb2NrCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDXN0YXJ0QWx0Q2hhaW4DDGJsb2NrSGFzaEhleAxyZWZlcmVuY2VIZXgFZXBvY2gEDGNoZWNrVmVyc2lvbgkBHnJlcXVpcmVFbFRvQ2xUcmFuc2ZlcnNEaXNhYmxlZAADCQAAAgUMY2hlY2tWZXJzaW9uBQxjaGVja1ZlcnNpb24EDmNoZWNrQmxvY2tIYXNoCQERdmFsaWRhdGVCbG9ja0hhc2gBBQxibG9ja0hhc2hIZXgDCQAAAgUOY2hlY2tCbG9ja0hhc2gFDmNoZWNrQmxvY2tIYXNoBApjaGVja0Vwb2NoCQESZW5zdXJlQ29ycmVjdEVwb2NoAQUFZXBvY2gDCQAAAgUKY2hlY2tFcG9jaAUKY2hlY2tFcG9jaAQOY2hlY2tHZW5lcmF0b3IJARFlbnN1cmVNaW5pbmdFcG9jaAEIBQFpDG9yaWdpbkNhbGxlcgMJAAACBQ5jaGVja0dlbmVyYXRvcgUOY2hlY2tHZW5lcmF0b3IEDSR0MDE5Njk4MTk4MDIJAQlibG9ja01ldGEBBQxyZWZlcmVuY2VIZXgEDnJlZkNoYWluSGVpZ2h0CAUNJHQwMTk2OTgxOTgwMgJfMQQIcmVmRXBvY2gIBQ0kdDAxOTY5ODE5ODAyAl8yBAZyZWZSZWYIBQ0kdDAxOTY5ODE5ODAyAl8zBAxyZWZHZW5lcmF0b3IIBQ0kdDAxOTY5ODE5ODAyAl80BAtyZWZJZ25vcmVkMQgFDSR0MDE5Njk4MTk4MDICXzUEC3JlZklnbm9yZWQyCAUNJHQwMTk2OTgxOTgwMgJfNgQOZmluYWxpemVkRXBvY2gICQEJYmxvY2tNZXRhAQkBEUBleHRyTmF0aXZlKDEwNTgpAQURZmluYWxpemVkQmxvY2tLZXkCXzIECGVwb2NoUmVmAwkAZwIFCHJlZkVwb2NoBQ5maW5hbGl6ZWRFcG9jaAUIcmVmRXBvY2gJAAIBCQCsAgIJAKwCAgkArAICCQCsAgICI2NhbiBub3Qgc3RhcnQgYWx0IGNoYWluIGZyb20gZXBvY2ggCQCkAwEFCHJlZkVwb2NoAggsIGVwb2NoIAkApAMBBQ5maW5hbGl6ZWRFcG9jaAINIGlzIGZpbmFsaXplZAQKY2hlY2tDaGFpbgkBHWVuc3VyZUV4cGVjdGVkT3JJbmFjdGl2ZUNoYWluAwgFAWkMb3JpZ2luQ2FsbGVyBQttYWluQ2hhaW5JZAUMcmVmZXJlbmNlSGV4AwkAAAIFCmNoZWNrQ2hhaW4FCmNoZWNrQ2hhaW4ECm5ld0NoYWluSWQJAGQCCQELdmFsdWVPckVsc2UCCQCfCAEFDmxhc3RDaGFpbklkS2V5AAAAAQQObmV3Q2hhaW5IZWlnaHQJAGQCCAkBCWJsb2NrTWV0YQEFDHJlZmVyZW5jZUhleAJfMQABBAxuZXdCbG9ja01ldGEJAMsBAgkAywECCQDLAQIJAJoDAQUObmV3Q2hhaW5IZWlnaHQJAJoDAQUGaGVpZ2h0CQDdBAEFDHJlZmVyZW5jZUhleAgIBQFpDG9yaWdpbkNhbGxlcgVieXRlcwQNdGhpc0Vwb2NoTWV0YQQHJG1hdGNoMAkBCWVwb2NoTWV0YQEFBmhlaWdodAMJAAECBQckbWF0Y2gwAgRVbml0CQELU3RyaW5nRW50cnkCCQEMZXBvY2hNZXRhS2V5AQUGaGVpZ2h0CQCsAgIJAKwCAgkArAICCQCsAgIJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBQNTRVAJAKQDAQUIZXBvY2hSZWYFA1NFUAUMYmxvY2tIYXNoSGV4BAVvdGhlcgUHJG1hdGNoMAkAAgECFUVwb2NoIGFscmVhZHkgc3RhcnRlZAkAzAgCBQ10aGlzRXBvY2hNZXRhCQDMCAIJAQtCaW5hcnlFbnRyeQIJAKwCAgUKYmxvY2tNZXRhSwUMYmxvY2tIYXNoSGV4BQxuZXdCbG9ja01ldGEJAMwIAgkBC1N0cmluZ0VudHJ5AgkBFGNoYWluRmlyc3RCbG9ja0lkS2V5AQUKbmV3Q2hhaW5JZAUMYmxvY2tIYXNoSGV4CQDMCAIJAQtTdHJpbmdFbnRyeQIJAQxjaGFpbk1ldGFLZXkBBQpuZXdDaGFpbklkCQCsAgIJAKwCAgkApAMBBQ5uZXdDaGFpbkhlaWdodAUDU0VQBQxibG9ja0hhc2hIZXgJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ9taW5lckNoYWluSWRLZXkBCAUBaQxvcmlnaW5DYWxsZXIFCm5ld0NoYWluSWQJAMwIAgkBDEludGVnZXJFbnRyeQIJARJjaGFpbkxhc3RIZWlnaHRLZXkCBQpuZXdDaGFpbklkCAUBaQxvcmlnaW5DYWxsZXIFDm5ld0NoYWluSGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQESY2hhaW5MYXN0SGVpZ2h0S2V5AgULbWFpbkNoYWluSWQIBQFpDG9yaWdpbkNhbGxlcgUObmV3Q2hhaW5IZWlnaHQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDXN1cHBvcnRlcnNLZXkBBQpuZXdDaGFpbklkCQClCAEIBQFpDG9yaWdpbkNhbGxlcgkAzAgCCQEMSW50ZWdlckVudHJ5AgUObGFzdENoYWluSWRLZXkFCm5ld0NoYWluSWQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARBzdGFydEFsdENoYWluX3YyBAxibG9ja0hhc2hIZXgMcmVmZXJlbmNlSGV4BWVwb2NoGmVsVG9DbFRyYW5zZmVyc1Jvb3RIYXNoSGV4BAxjaGVja1ZlcnNpb24JAR1yZXF1aXJlRWxUb0NsVHJhbnNmZXJzRW5hYmxlZAADCQAAAgUMY2hlY2tWZXJzaW9uBQxjaGVja1ZlcnNpb24EDmNoZWNrQmxvY2tIYXNoCQERdmFsaWRhdGVCbG9ja0hhc2gBBQxibG9ja0hhc2hIZXgDCQAAAgUOY2hlY2tCbG9ja0hhc2gFDmNoZWNrQmxvY2tIYXNoBApjaGVja0Vwb2NoCQESZW5zdXJlQ29ycmVjdEVwb2NoAQUFZXBvY2gDCQAAAgUKY2hlY2tFcG9jaAUKY2hlY2tFcG9jaAQOY2hlY2tHZW5lcmF0b3IJARFlbnN1cmVNaW5pbmdFcG9jaAEIBQFpDG9yaWdpbkNhbGxlcgMJAAACBQ5jaGVja0dlbmVyYXRvcgUOY2hlY2tHZW5lcmF0b3IEDSR0MDIxNjEyMjE3MTYJAQlibG9ja01ldGEBBQxyZWZlcmVuY2VIZXgEDnJlZkNoYWluSGVpZ2h0CAUNJHQwMjE2MTIyMTcxNgJfMQQIcmVmRXBvY2gIBQ0kdDAyMTYxMjIxNzE2Al8yBAZyZWZSZWYIBQ0kdDAyMTYxMjIxNzE2Al8zBAxyZWZHZW5lcmF0b3IIBQ0kdDAyMTYxMjIxNzE2Al80BAtyZWZJZ25vcmVkMQgFDSR0MDIxNjEyMjE3MTYCXzUEC3JlZklnbm9yZWQyCAUNJHQwMjE2MTIyMTcxNgJfNgQOZmluYWxpemVkRXBvY2gICQEJYmxvY2tNZXRhAQkBEUBleHRyTmF0aXZlKDEwNTgpAQURZmluYWxpemVkQmxvY2tLZXkCXzIECGVwb2NoUmVmAwkAZwIFCHJlZkVwb2NoBQ5maW5hbGl6ZWRFcG9jaAUIcmVmRXBvY2gJAAIBCQCsAgIJAKwCAgkArAICCQCsAgICI2NhbiBub3Qgc3RhcnQgYWx0IGNoYWluIGZyb20gZXBvY2ggCQCkAwEFCHJlZkVwb2NoAggsIGVwb2NoIAkApAMBBQ5maW5hbGl6ZWRFcG9jaAINIGlzIGZpbmFsaXplZAQKY2hlY2tDaGFpbgkBHWVuc3VyZUV4cGVjdGVkT3JJbmFjdGl2ZUNoYWluAwgFAWkMb3JpZ2luQ2FsbGVyBQttYWluQ2hhaW5JZAUMcmVmZXJlbmNlSGV4AwkAAAIFCmNoZWNrQ2hhaW4FCmNoZWNrQ2hhaW4ECm5ld0NoYWluSWQJAGQCCQELdmFsdWVPckVsc2UCCQCfCAEFDmxhc3RDaGFpbklkS2V5AAAAAQQObmV3Q2hhaW5IZWlnaHQJAGQCCAkBCWJsb2NrTWV0YQEFDHJlZmVyZW5jZUhleAJfMQABBA10aGlzRXBvY2hNZXRhBAckbWF0Y2gwCQEJZXBvY2hNZXRhAQUGaGVpZ2h0AwkAAQIFByRtYXRjaDACBFVuaXQJAQtTdHJpbmdFbnRyeQIJAQxlcG9jaE1ldGFLZXkBBQZoZWlnaHQJAKwCAgkArAICCQCsAgIJAKwCAgkApQgBCAUBaQxvcmlnaW5DYWxsZXIFA1NFUAkApAMBBQhlcG9jaFJlZgUDU0VQBQxibG9ja0hhc2hIZXgEBW90aGVyBQckbWF0Y2gwCQACAQIVRXBvY2ggYWxyZWFkeSBzdGFydGVkCQDMCAIFDXRoaXNFcG9jaE1ldGEJAMwIAgkBEG1rQmxvY2tNZXRhRW50cnkGBQxibG9ja0hhc2hIZXgFDm5ld0NoYWluSGVpZ2h0BQxyZWZlcmVuY2VIZXgIBQFpDG9yaWdpbkNhbGxlcgUKbmV3Q2hhaW5JZAUaZWxUb0NsVHJhbnNmZXJzUm9vdEhhc2hIZXgJAMwIAgkBC1N0cmluZ0VudHJ5AgkBFGNoYWluRmlyc3RCbG9ja0lkS2V5AQUKbmV3Q2hhaW5JZAUMYmxvY2tIYXNoSGV4CQDMCAIJAQtTdHJpbmdFbnRyeQIJAQxjaGFpbk1ldGFLZXkBBQpuZXdDaGFpbklkCQCsAgIJAKwCAgkApAMBBQ5uZXdDaGFpbkhlaWdodAUDU0VQBQxibG9ja0hhc2hIZXgJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ9taW5lckNoYWluSWRLZXkBCAUBaQxvcmlnaW5DYWxsZXIFCm5ld0NoYWluSWQJAMwIAgkBDEludGVnZXJFbnRyeQIJARJjaGFpbkxhc3RIZWlnaHRLZXkCBQpuZXdDaGFpbklkCAUBaQxvcmlnaW5DYWxsZXIFDm5ld0NoYWluSGVpZ2h0CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQESY2hhaW5MYXN0SGVpZ2h0S2V5AgULbWFpbkNoYWluSWQIBQFpDG9yaWdpbkNhbGxlcgUObmV3Q2hhaW5IZWlnaHQJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDXN1cHBvcnRlcnNLZXkBBQpuZXdDaGFpbklkCQClCAEIBQFpDG9yaWdpbkNhbGxlcgkAzAgCCQEMSW50ZWdlckVudHJ5AgUObGFzdENoYWluSWRLZXkFCm5ld0NoYWluSWQFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ5leHRlbmRBbHRDaGFpbgQHY2hhaW5JZAxibG9ja0hhc2hIZXgMcmVmZXJlbmNlSGV4BWVwb2NoBAxjaGVja1ZlcnNpb24JAR5yZXF1aXJlRWxUb0NsVHJhbnNmZXJzRGlzYWJsZWQAAwkAAAIFDGNoZWNrVmVyc2lvbgUMY2hlY2tWZXJzaW9uBA5jaGVja0Jsb2NrSGFzaAkBEXZhbGlkYXRlQmxvY2tIYXNoAQUMYmxvY2tIYXNoSGV4AwkAAAIFDmNoZWNrQmxvY2tIYXNoBQ5jaGVja0Jsb2NrSGFzaAQKY2hlY2tFcG9jaAkBEmVuc3VyZUNvcnJlY3RFcG9jaAEFBWVwb2NoAwkAAAIFCmNoZWNrRXBvY2gFCmNoZWNrRXBvY2gEDmNoZWNrR2VuZXJhdG9yCQERZW5zdXJlTWluaW5nRXBvY2gBCAUBaQxvcmlnaW5DYWxsZXIDCQAAAgUOY2hlY2tHZW5lcmF0b3IFDmNoZWNrR2VuZXJhdG9yBBNjaGFpbkZpcnN0QmxvY2tNZXRhCQEJYmxvY2tNZXRhAQkBEUBleHRyTmF0aXZlKDEwNTgpAQkBFGNoYWluRmlyc3RCbG9ja0lkS2V5AQUHY2hhaW5JZAQKY2hlY2tDaGFpbgkBHWVuc3VyZUV4cGVjdGVkT3JJbmFjdGl2ZUNoYWluAwgFAWkMb3JpZ2luQ2FsbGVyBQdjaGFpbklkCQDcBAEIBRNjaGFpbkZpcnN0QmxvY2tNZXRhAl8zAwkAAAIFCmNoZWNrQ2hhaW4FCmNoZWNrQ2hhaW4EDSR0MDIzOTU1MjQwMDkJAQljaGFpbk1ldGEBBQdjaGFpbklkBAtjaGFpbkhlaWdodAgFDSR0MDIzOTU1MjQwMDkCXzEEDmNoYWluTGFzdEJsb2NrCAUNJHQwMjM5NTUyNDAwOQJfMgQOY2hlY2tSZWZlcmVuY2UJARJpc1JlZmVyZW5jZUNvcnJlY3QCBQxyZWZlcmVuY2VIZXgFDmNoYWluTGFzdEJsb2NrAwkAAAIFDmNoZWNrUmVmZXJlbmNlBQ5jaGVja1JlZmVyZW5jZQQObmV3Q2hhaW5IZWlnaHQJAGQCBQtjaGFpbkhlaWdodAABBAlwcmV2RXBvY2gICQEJYmxvY2tNZXRhAQUMcmVmZXJlbmNlSGV4Al8yBBN1cGRhdGVNYWluQ2hhaW5EYXRhAwkAZgIJARFzdXBwb3J0aW5nQmFsYW5jZQEFB2NoYWluSWQJAGkCBRRjb21wdXRlZFRvdGFsQmFsYW5jZQACBAtsYXN0Q2hhaW5JZAkBC3ZhbHVlT3JFbHNlAgkAnwgBBQ5sYXN0Q2hhaW5JZEtleQAABBR1cGRhdGVGaW5hbGl6ZWRCbG9jawkBHWdldFVwZGF0ZUZpbmFsaXplZEJsb2NrQWN0aW9uAwgFAWkMb3JpZ2luQ2FsbGVyBQxibG9ja0hhc2hIZXgFCXByZXZFcG9jaAkAzggCCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEUY2hhaW5Gb3JrZWRIZWlnaHRLZXkBBQttYWluQ2hhaW5JZAgFE2NoYWluRmlyc3RCbG9ja01ldGECXzEJAMwIAgkBDEludGVnZXJFbnRyeQIFDm1haW5DaGFpbklkS2V5BQdjaGFpbklkCQDMCAIJAQxJbnRlZ2VyRW50cnkCBRdmaXJzdFZhbGlkQWx0Q2hhaW5JZEtleQkAZAIFC2xhc3RDaGFpbklkAAEFA25pbAUUdXBkYXRlRmluYWxpemVkQmxvY2sFA25pbAQNdGhpc0Vwb2NoTWV0YQQHJG1hdGNoMAkBCWVwb2NoTWV0YQEFBmhlaWdodAMJAAECBQckbWF0Y2gwAgRVbml0CQELU3RyaW5nRW50cnkCCQEMZXBvY2hNZXRhS2V5AQUGaGVpZ2h0CQCsAgIJAKwCAgkArAICCQCsAgIJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBQNTRVAJAKQDAQUJcHJldkVwb2NoBQNTRVAFDGJsb2NrSGFzaEhleAQFb3RoZXIFByRtYXRjaDAJAAIBAhVFcG9jaCBhbHJlYWR5IHN0YXJ0ZWQEHXVwZGF0ZU1haW5DaGFpbkxhc3RNaW5lZEJsb2NrAwMJAAACBRN1cGRhdGVNYWluQ2hhaW5EYXRhBQNuaWwJAQIhPQIJAQt2YWx1ZU9yRWxzZQIJAQxtaW5lckNoYWluSWQBCAUBaQxvcmlnaW5DYWxsZXIAAAUHY2hhaW5JZAcJAMwIAgkBDEludGVnZXJFbnRyeQIJARJjaGFpbkxhc3RIZWlnaHRLZXkCBQttYWluQ2hhaW5JZAgFAWkMb3JpZ2luQ2FsbGVyCAUTY2hhaW5GaXJzdEJsb2NrTWV0YQJfMQUDbmlsBQNuaWwEDG5ld0Jsb2NrTWV0YQkAywECCQDLAQIJAMsBAgkAmgMBBQ5uZXdDaGFpbkhlaWdodAkAmgMBBQZoZWlnaHQJAN0EAQUMcmVmZXJlbmNlSGV4CAgFAWkMb3JpZ2luQ2FsbGVyBWJ5dGVzCQDOCAIJAM4IAgkAzggCCQDMCAIJAQtCaW5hcnlFbnRyeQIJAKwCAgUKYmxvY2tNZXRhSwUMYmxvY2tIYXNoSGV4BQxuZXdCbG9ja01ldGEJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDGNoYWluTWV0YUtleQEFB2NoYWluSWQJAKwCAgkArAICCQCkAwEFDm5ld0NoYWluSGVpZ2h0BQNTRVAFDGJsb2NrSGFzaEhleAkAzAgCBQ10aGlzRXBvY2hNZXRhCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEPbWluZXJDaGFpbklkS2V5AQgFAWkMb3JpZ2luQ2FsbGVyBQdjaGFpbklkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQESY2hhaW5MYXN0SGVpZ2h0S2V5AgUHY2hhaW5JZAgFAWkMb3JpZ2luQ2FsbGVyBQ5uZXdDaGFpbkhlaWdodAUDbmlsBRN1cGRhdGVNYWluQ2hhaW5EYXRhCQEMYWRkU3VwcG9ydGVyAgUHY2hhaW5JZAgFAWkMb3JpZ2luQ2FsbGVyBR11cGRhdGVNYWluQ2hhaW5MYXN0TWluZWRCbG9jawkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpARFleHRlbmRBbHRDaGFpbl92MgUHY2hhaW5JZAxibG9ja0hhc2hIZXgMcmVmZXJlbmNlSGV4BWVwb2NoGmVsVG9DbFRyYW5zZmVyc1Jvb3RIYXNoSGV4BAxjaGVja1ZlcnNpb24JAR1yZXF1aXJlRWxUb0NsVHJhbnNmZXJzRW5hYmxlZAADCQAAAgUMY2hlY2tWZXJzaW9uBQxjaGVja1ZlcnNpb24EDmNoZWNrQmxvY2tIYXNoCQERdmFsaWRhdGVCbG9ja0hhc2gBBQxibG9ja0hhc2hIZXgDCQAAAgUOY2hlY2tCbG9ja0hhc2gFDmNoZWNrQmxvY2tIYXNoBApjaGVja0Vwb2NoCQESZW5zdXJlQ29ycmVjdEVwb2NoAQUFZXBvY2gDCQAAAgUKY2hlY2tFcG9jaAUKY2hlY2tFcG9jaAQOY2hlY2tHZW5lcmF0b3IJARFlbnN1cmVNaW5pbmdFcG9jaAEIBQFpDG9yaWdpbkNhbGxlcgMJAAACBQ5jaGVja0dlbmVyYXRvcgUOY2hlY2tHZW5lcmF0b3IEE2NoYWluRmlyc3RCbG9ja01ldGEJAQlibG9ja01ldGEBCQERQGV4dHJOYXRpdmUoMTA1OCkBCQEUY2hhaW5GaXJzdEJsb2NrSWRLZXkBBQdjaGFpbklkBApjaGVja0NoYWluCQEdZW5zdXJlRXhwZWN0ZWRPckluYWN0aXZlQ2hhaW4DCAUBaQxvcmlnaW5DYWxsZXIFB2NoYWluSWQJANwEAQgFE2NoYWluRmlyc3RCbG9ja01ldGECXzMDCQAAAgUKY2hlY2tDaGFpbgUKY2hlY2tDaGFpbgQNJHQwMjY2MTIyNjY2NgkBCWNoYWluTWV0YQEFB2NoYWluSWQEC2NoYWluSGVpZ2h0CAUNJHQwMjY2MTIyNjY2NgJfMQQOY2hhaW5MYXN0QmxvY2sIBQ0kdDAyNjYxMjI2NjY2Al8yBA5jaGVja1JlZmVyZW5jZQkBEmlzUmVmZXJlbmNlQ29ycmVjdAIFDHJlZmVyZW5jZUhleAUOY2hhaW5MYXN0QmxvY2sDCQAAAgUOY2hlY2tSZWZlcmVuY2UFDmNoZWNrUmVmZXJlbmNlBA5uZXdDaGFpbkhlaWdodAkAZAIFC2NoYWluSGVpZ2h0AAEECXByZXZFcG9jaAgJAQlibG9ja01ldGEBBQxyZWZlcmVuY2VIZXgCXzIEE3VwZGF0ZU1haW5DaGFpbkRhdGEDCQBmAgkBEXN1cHBvcnRpbmdCYWxhbmNlAQUHY2hhaW5JZAkAaQIFFGNvbXB1dGVkVG90YWxCYWxhbmNlAAIEC2xhc3RDaGFpbklkCQELdmFsdWVPckVsc2UCCQCfCAEFDmxhc3RDaGFpbklkS2V5AAAEFHVwZGF0ZUZpbmFsaXplZEJsb2NrCQEdZ2V0VXBkYXRlRmluYWxpemVkQmxvY2tBY3Rpb24DCAUBaQxvcmlnaW5DYWxsZXIFDGJsb2NrSGFzaEhleAUJcHJldkVwb2NoCQDOCAIJAMwIAgkBDEludGVnZXJFbnRyeQIJARRjaGFpbkZvcmtlZEhlaWdodEtleQEFC21haW5DaGFpbklkCAUTY2hhaW5GaXJzdEJsb2NrTWV0YQJfMQkAzAgCCQEMSW50ZWdlckVudHJ5AgUObWFpbkNoYWluSWRLZXkFB2NoYWluSWQJAMwIAgkBDEludGVnZXJFbnRyeQIFF2ZpcnN0VmFsaWRBbHRDaGFpbklkS2V5CQBkAgULbGFzdENoYWluSWQAAQUDbmlsBRR1cGRhdGVGaW5hbGl6ZWRCbG9jawUDbmlsBA10aGlzRXBvY2hNZXRhBAckbWF0Y2gwCQEJZXBvY2hNZXRhAQUGaGVpZ2h0AwkAAQIFByRtYXRjaDACBFVuaXQJAQtTdHJpbmdFbnRyeQIJAQxlcG9jaE1ldGFLZXkBBQZoZWlnaHQJAKwCAgkArAICCQCsAgIJAKwCAgkApQgBCAUBaQxvcmlnaW5DYWxsZXIFA1NFUAkApAMBBQlwcmV2RXBvY2gFA1NFUAUMYmxvY2tIYXNoSGV4BAVvdGhlcgUHJG1hdGNoMAkAAgECFUVwb2NoIGFscmVhZHkgc3RhcnRlZAQddXBkYXRlTWFpbkNoYWluTGFzdE1pbmVkQmxvY2sDAwkAAAIFE3VwZGF0ZU1haW5DaGFpbkRhdGEFA25pbAkBAiE9AgkBC3ZhbHVlT3JFbHNlAgkBDG1pbmVyQ2hhaW5JZAEIBQFpDG9yaWdpbkNhbGxlcgAABQdjaGFpbklkBwkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEmNoYWluTGFzdEhlaWdodEtleQIFC21haW5DaGFpbklkCAUBaQxvcmlnaW5DYWxsZXIIBRNjaGFpbkZpcnN0QmxvY2tNZXRhAl8xBQNuaWwFA25pbAkAzggCCQDOCAIJAM4IAgkAzAgCCQEQbWtCbG9ja01ldGFFbnRyeQYFDGJsb2NrSGFzaEhleAUObmV3Q2hhaW5IZWlnaHQFDHJlZmVyZW5jZUhleAgFAWkMb3JpZ2luQ2FsbGVyBQdjaGFpbklkBRplbFRvQ2xUcmFuc2ZlcnNSb290SGFzaEhleAkAzAgCCQELU3RyaW5nRW50cnkCCQEMY2hhaW5NZXRhS2V5AQUHY2hhaW5JZAkArAICCQCsAgIJAKQDAQUObmV3Q2hhaW5IZWlnaHQFA1NFUAUMYmxvY2tIYXNoSGV4CQDMCAIFDXRoaXNFcG9jaE1ldGEJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ9taW5lckNoYWluSWRLZXkBCAUBaQxvcmlnaW5DYWxsZXIFB2NoYWluSWQJAMwIAgkBDEludGVnZXJFbnRyeQIJARJjaGFpbkxhc3RIZWlnaHRLZXkCBQdjaGFpbklkCAUBaQxvcmlnaW5DYWxsZXIFDm5ld0NoYWluSGVpZ2h0BQNuaWwFE3VwZGF0ZU1haW5DaGFpbkRhdGEJAQxhZGRTdXBwb3J0ZXICBQdjaGFpbklkCAUBaQxvcmlnaW5DYWxsZXIFHXVwZGF0ZU1haW5DaGFpbkxhc3RNaW5lZEJsb2NrCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBBGpvaW4BDXJld2FyZEFkZHJlc3MKARJjaGVja1Jld2FyZEFkZHJlc3MBB2FkZHJlc3MEByRtYXRjaDAJAKEIAQkBCm1pbmVyUGtLZXkBBQdhZGRyZXNzAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAnBrBQckbWF0Y2gwAwkAAAIFAnBrCAUBaRVvcmlnaW5DYWxsZXJQdWJsaWNLZXkFBHVuaXQJAAIBCQCsAgIJAKwCAgkArAICAhFMMiBtaW5lciBhZGRyZXNzIAUHYWRkcmVzcwIYIGlzIGFscmVhZHkgbGlua2VkIHdpdGggCQDYBAEFAnBrBQR1bml0AwkBASEBCQEPaXNDb250cmFjdFNldHVwAAkAAgECH1RoZSBjb250cmFjdCBoYXMgbm90IHlldCBzZXQgdXADCQBmAgULTUlOX0JBTEFOQ0UICQDvBwEIBQFpDG9yaWdpbkNhbGxlcgpnZW5lcmF0aW5nCQACAQkArAICCQCsAgIJAKwCAgIhSW5zdWZmaWNpZW50IGdlbmVyYXRpbmcgYmFsYW5jZTogCQCkAwEICQDvBwEIBQFpDG9yaWdpbkNhbGxlcgpnZW5lcmF0aW5nAgwuIFJlcXVpcmVkOiAJAKQDAQULTUlOX0JBTEFOQ0UDCQECIT0CCQDIAQEFDXJld2FyZEFkZHJlc3MAFAkAAgECJXJld2FyZEFkZHJlc3Mgc2hvdWxkIGJlIGFuIEwyIGFkZHJlc3MDCQBnAgkAkAMBBQlhbGxNaW5lcnMAMgkAAgECD3RvbyBtYW55IG1pbmVycwoBDmNoZWNrRXhpc3RlbmNlAgZleGlzdHMFbWluZXIDBQZleGlzdHMGCQAAAgUFbWluZXIJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBA1hbHJlYWR5RXhpc3RzCgACJGwFCWFsbE1pbmVycwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAHCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQ5jaGVja0V4aXN0ZW5jZQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgNTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyAwUNYWxyZWFkeUV4aXN0cwUDbmlsBAhuZXdNaW5lcgkApQgBCAUBaQxvcmlnaW5DYWxsZXIEEHJld2FyZEFkZHJlc3NIZXgJANwEAQUNcmV3YXJkQWRkcmVzcwQFY2hlY2sJARJjaGVja1Jld2FyZEFkZHJlc3MBBRByZXdhcmRBZGRyZXNzSGV4AwkAAAIFBWNoZWNrBQVjaGVjawQJbmV3TWluZXJzAwkAAAIJAJADAQUJYWxsTWluZXJzAAAFCG5ld01pbmVyCQCsAgIJAKwCAgUMYWxsTWluZXJzU3RyBQNTRVAFCG5ld01pbmVyBBhkZWxldGVPbGRSZXdhcmRBZGRyZXNzUGsEByRtYXRjaDAJAKIIAQkBFW1pbmVyUmV3YXJkQWRkcmVzc0tleQEFCG5ld01pbmVyAwkAAQIFByRtYXRjaDACBlN0cmluZwQKb2xkQWRkcmVzcwUHJG1hdGNoMAMJAAACBQpvbGRBZGRyZXNzCQDcBAEFDXJld2FyZEFkZHJlc3MFA25pbAkAzAgCCQELRGVsZXRlRW50cnkBCQEKbWluZXJQa0tleQEFCm9sZEFkZHJlc3MFA25pbAUDbmlsCQDOCAIJAMwIAgkBC1N0cmluZ0VudHJ5AgUMYWxsTWluZXJzS2V5BQluZXdNaW5lcnMJAMwIAgkBC1N0cmluZ0VudHJ5AgkBFW1pbmVyUmV3YXJkQWRkcmVzc0tleQEFCG5ld01pbmVyCQCsAgICAjB4BRByZXdhcmRBZGRyZXNzSGV4CQDMCAIJAQtCaW5hcnlFbnRyeQIJAQptaW5lclBrS2V5AQUQcmV3YXJkQWRkcmVzc0hleAgFAWkVb3JpZ2luQ2FsbGVyUHVibGljS2V5BQNuaWwFGGRlbGV0ZU9sZFJld2FyZEFkZHJlc3NQawkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQVsZWF2ZQAEDGxlYXZpbmdNaW5lcgkApQgBCAUBaQxvcmlnaW5DYWxsZXIKARBza2lwTGVhdmluZ01pbmVyAgNhY2MFbWluZXIDCQAAAgUFbWluZXIFDGxlYXZpbmdNaW5lcgUDYWNjCQDNCAIFA2FjYwUFbWluZXIED3JlbWFpbmluZ01pbmVycwoAAiRsBQlhbGxNaW5lcnMKAAIkcwkAkAMBBQIkbAoABSRhY2MwBQNuaWwKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBEHNraXBMZWF2aW5nTWluZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDUwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgQNcmV3YXJkQWRkcktleQkBFW1pbmVyUmV3YXJkQWRkcmVzc0tleQEFDGxlYXZpbmdNaW5lcgQRcHJldlJld2FyZEFkZHJlc3MJARN2YWx1ZU9yRXJyb3JNZXNzYWdlAgkAnQgCBQR0aGlzBQ1yZXdhcmRBZGRyS2V5AhZtaW5lciBoYXMgbmV2ZXIgam9pbmVkAwkAAAIFDnRoaXNFcG9jaE1pbmVyCAUBaQxvcmlnaW5DYWxsZXIJAAIBAhxkZXNpZ25hdGVkIG1pbmVyIGNhbid0IGxlYXZlCQDMCAIJAQtTdHJpbmdFbnRyeQIFDGFsbE1pbmVyc0tleQkAugkCBQ9yZW1haW5pbmdNaW5lcnMFA1NFUAkAzAgCCQELRGVsZXRlRW50cnkBBQ1yZXdhcmRBZGRyS2V5CQDMCAIJAQtEZWxldGVFbnRyeQEJAQptaW5lclBrS2V5AQURcHJldlJld2FyZEFkZHJlc3MFA25pbAFpAQh3aXRoZHJhdwQMYmxvY2tIYXNoSGV4C21lcmtsZVByb29mFHRyYW5zZmVySW5kZXhJbkJsb2NrBmFtb3VudAQPY2hlY2tBY3RpdmF0aW9uCQEdcmVxdWlyZUVsVG9DbFRyYW5zZmVyc0VuYWJsZWQAAwkAAAIFD2NoZWNrQWN0aXZhdGlvbgUPY2hlY2tBY3RpdmF0aW9uBBF3aXRoZHJhd0Jsb2NrTWV0YQkBCWJsb2NrTWV0YQEFDGJsb2NrSGFzaEhleAQTd2l0aGRyYXdCbG9ja0hlaWdodAgFEXdpdGhkcmF3QmxvY2tNZXRhAl8xBBRmaW5hbGl6ZWRCbG9ja0hlaWdodAgJAQlibG9ja01ldGEBCQERQGV4dHJOYXRpdmUoMTA1OCkBBRFmaW5hbGl6ZWRCbG9ja0tleQJfMQQYbWFpbkNoYWluTGFzdEJsb2NrSGVpZ2h0CAkBCWJsb2NrTWV0YQEFEm1haW5DaGFpbkxhc3RCbG9jawJfMQMJAGYCBRN3aXRoZHJhd0Jsb2NrSGVpZ2h0BRRmaW5hbGl6ZWRCbG9ja0hlaWdodAkAAgEJAKwCAgkArAICCQCsAgICCkVMIGJsb2NrICMJAKQDAQUTd2l0aGRyYXdCbG9ja0hlaWdodAItIGlzIG5vdCBmaW5hbGl6ZWQuIFRoZSBjdXJyZW50IGZpbmFsaXplZCBpcyAjCQCkAwEFFGZpbmFsaXplZEJsb2NrSGVpZ2h0BBR3aXRoZHJhd0Jsb2NrQ2hhaW5JZAgFEXdpdGhkcmF3QmxvY2tNZXRhAl81BAtpc01haW5DaGFpbgkAAAIFFHdpdGhkcmF3QmxvY2tDaGFpbklkBQttYWluQ2hhaW5JZAQScmVsYXRlc1RvTWFpbkNoYWluBAckbWF0Y2gwCQCfCAEJARRjaGFpbkZvcmtlZEhlaWdodEtleQEFFHdpdGhkcmF3QmxvY2tDaGFpbklkAwkAAQIFByRtYXRjaDACA0ludAQMZm9ya2VkSGVpZ2h0BQckbWF0Y2gwCQBmAgUMZm9ya2VkSGVpZ2h0BRN3aXRoZHJhd0Jsb2NrSGVpZ2h0CQACAQkArAICCQCsAgIJAKwCAgUMYmxvY2tIYXNoSGV4Ah0gaXMgb24gYW4gYWx0ZXJuYXRpdmUgY2hhaW4gIwkApAMBBRR3aXRoZHJhd0Jsb2NrQ2hhaW5JZAI4IHRoYXQgd2FzIG5vdCBhcHByb3ZlZCBieSBtYWpvcml0eS4gV2FpdCBmb3Igc29tZSBibG9ja3MDAwULaXNNYWluQ2hhaW4GBRJyZWxhdGVzVG9NYWluQ2hhaW4ECXJlY2lwaWVudAgFAWkMb3JpZ2luQ2FsbGVyBA9yZWNpcGllbnRQa0hhc2gJAMkBAgkAygECCAUJcmVjaXBpZW50BWJ5dGVzAAIFFFBVQkxJQ19LRVlfSEFTSF9TSVpFBA96ZXJvQW1vdW50Qnl0ZXMBLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAthbW91bnRCeXRlcwkAmgMBBQZhbW91bnQEC2VsRXZlbnREYXRhCQDLAQIJAMsBAgUPcmVjaXBpZW50UGtIYXNoCQDJAQIFD3plcm9BbW91bnRCeXRlcwkAZQIJAMgBAQUPemVyb0Ftb3VudEJ5dGVzCQDIAQEFC2Ftb3VudEJ5dGVzBQthbW91bnRCeXRlcwQRZWxFdmVudERhdGFEaWdlc3QJAPAVAQULZWxFdmVudERhdGEEEmNhbGN1bGF0ZWRSb290SGFzaAkAvQUDBQttZXJrbGVQcm9vZgURZWxFdmVudERhdGFEaWdlc3QFFHRyYW5zZmVySW5kZXhJbkJsb2NrBBBleHBlY3RlZFJvb3RIYXNoCAURd2l0aGRyYXdCbG9ja01ldGECXzYDCQAAAgUSY2FsY3VsYXRlZFJvb3RIYXNoBRBleHBlY3RlZFJvb3RIYXNoBAd0b2tlbklkCQDZBAEJARFAZXh0ck5hdGl2ZSgxMDU4KQEFCnRva2VuSWRLZXkEDHRyYW5zZmVyc0tleQkBF2Jsb2NrRWxUb0NsVHJhbnNmZXJzS2V5AQUMYmxvY2tIYXNoSGV4CQDMCAIJAQdSZWlzc3VlAwUHdG9rZW5JZAUGYW1vdW50BgkAzAgCCQEOU2NyaXB0VHJhbnNmZXIDBQlyZWNpcGllbnQFBmFtb3VudAUHdG9rZW5JZAkAzAgCCQELU3RyaW5nRW50cnkCBQx0cmFuc2ZlcnNLZXkJAQlzZXRPckZhaWwCCQELdmFsdWVPckVsc2UCCQCiCAEFDHRyYW5zZmVyc0tleQIABRR0cmFuc2ZlckluZGV4SW5CbG9jawUDbmlsCQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICFEV4cGVjdGVkIHJvb3QgaGFzaDogCQDcBAEFEGV4cGVjdGVkUm9vdEhhc2gCBywgZ290OiAJANwEAQUSY2FsY3VsYXRlZFJvb3RIYXNoAhUuIEV2ZW50IGRhdGEgZGlnZXN0OiAJANoEAQURZWxFdmVudERhdGFEaWdlc3QJAAIBCQCsAgIJAKwCAgIJRXhwZWN0ZWQgBQxibG9ja0hhc2hIZXgCLyB0byBiZSBlaXRoZXIgb24gdGhlIG1haW4gY2hhaW4gb3IgcmVsYXRlIHRvIGl0CQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBBXNldHVwBBNnZW5lc2lzQmxvY2tIYXNoSGV4EW1pbmVyUmV3YXJkSW5Hd2VpGXN0YWtpbmdDb250cmFjdEFkZHJlc3NCNTgSZWxCcmlkZ2VBZGRyZXNzSGV4AwkBD2lzQ29udHJhY3RTZXR1cAAJAAIBAiRUaGUgY29udHJhY3QgaGFzIGJlZW4gYWxyZWFkeSBzZXQgdXADCQBmAgAABRFtaW5lclJld2FyZEluR3dlaQkAAgECJFRoZSBtaW5lciByZXdhcmQgbXVzdCBiZSBub25uZWdhdGl2ZQQQZ2VuZXNpc0Jsb2NrSGFzaAkA3QQBBRNnZW5lc2lzQmxvY2tIYXNoSGV4BAdlbXB0eVBrASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQTZ2VuZXNpc01pbmVyQWRkcmVzcwkApwgBBQdlbXB0eVBrBBdnZW5lc2lzRXRoUmV3YXJkQWRkcmVzcwEUAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWdlbmVzaXNCbG9ja1JlZmVyZW5jZUhhc2gCQDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAEBWlzc3VlCQDCCAUCBVVOSVQwAgxOYXRpdmUgdG9rZW4AAAAIBgQHdG9rZW5JZAkAuAgBBQVpc3N1ZQkAzAgCCQEQbWtCbG9ja01ldGFFbnRyeQYFE2dlbmVzaXNCbG9ja0hhc2hIZXgAAAUZZ2VuZXNpc0Jsb2NrUmVmZXJlbmNlSGFzaAUTZ2VuZXNpc01pbmVyQWRkcmVzcwULbWFpbkNoYWluSWQCAAkAzAgCCQELU3RyaW5nRW50cnkCCQEUY2hhaW5GaXJzdEJsb2NrSWRLZXkBAAAFE2dlbmVzaXNCbG9ja0hhc2hIZXgJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDGNoYWluTWV0YUtleQEAAAkArAICAgIwLAUTZ2VuZXNpc0Jsb2NrSGFzaEhleAkAzAgCCQEMSW50ZWdlckVudHJ5AgUObWluZXJSZXdhcmRLZXkFEW1pbmVyUmV3YXJkSW5Hd2VpCQDMCAIJAQtTdHJpbmdFbnRyeQIFGXN0YWtpbmdDb250cmFjdEFkZHJlc3NLZXkFGXN0YWtpbmdDb250cmFjdEFkZHJlc3NCNTgJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDGVwb2NoTWV0YUtleQEFBmhlaWdodAkArAICCQCsAgIJAKUIAQUTZ2VuZXNpc01pbmVyQWRkcmVzcwIDLDAsBRNnZW5lc2lzQmxvY2tIYXNoSGV4CQDMCAIJAQtTdHJpbmdFbnRyeQIFEWZpbmFsaXplZEJsb2NrS2V5BRNnZW5lc2lzQmxvY2tIYXNoSGV4CQDMCAIJAQxJbnRlZ2VyRW50cnkCBRNwcmV2UmFuZGFvSGVpZ2h0S2V5AAAJAMwIAgkBDEludGVnZXJFbnRyeQIFF2VsVG9DbFRyYW5zZmVyc0Vwb2NoS2V5AAAJAMwIAgUFaXNzdWUJAMwIAgkBC1N0cmluZ0VudHJ5AgUKdG9rZW5JZEtleQkA2AQBBQd0b2tlbklkCQDMCAIJAQtTdHJpbmdFbnRyeQIFEmVsQnJpZGdlQWRkcmVzc0tleQkArAICAgIweAUSZWxCcmlkZ2VBZGRyZXNzSGV4BQNuaWwBaQEUc2V0dXBFbFRvQ2xUcmFuc2ZlcnMCEGFjdGl2YXRpb25IZWlnaHQSZWxCcmlkZ2VBZGRyZXNzSGV4AwkBCWlzRGVmaW5lZAEJAJ8IAQUXZWxUb0NsVHJhbnNmZXJzRXBvY2hLZXkJAAIBAiVFTCB0byBDTCB0cmFuc2ZlcnMgZmVhdHVyZSB3YXMgc2V0IHVwBAVpc3N1ZQkAwggFAgVVTklUMAIMTmF0aXZlIHRva2VuAAAACAYEB3Rva2VuSWQJALgIAQUFaXNzdWUJAMwIAgkBDEludGVnZXJFbnRyeQIFF2VsVG9DbFRyYW5zZmVyc0Vwb2NoS2V5BRBhY3RpdmF0aW9uSGVpZ2h0CQDMCAIFBWlzc3VlCQDMCAIJAQtTdHJpbmdFbnRyeQIFCnRva2VuSWRLZXkJANgEAQUHdG9rZW5JZAkAzAgCCQELU3RyaW5nRW50cnkCBRJlbEJyaWRnZUFkZHJlc3NLZXkJAKwCAgICMHgFEmVsQnJpZGdlQWRkcmVzc0hleAUDbmlsACfyX+E=", "height": 3197802, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: FNjNKot193WRkSkpK9FPbckjMik1WXVhi6NsfbDPkqLL Next: Eh7NKbyaoxgEJ4BwqmwtiBQho4gcdExwKQ9ZwLmSAcYj Diff:
Old | New | Differences | |
---|---|---|---|
12 | 12 | let BLOCK_HASH_SIZE = 32 | |
13 | 13 | ||
14 | 14 | let ADDRESS_SIZE = 26 | |
15 | + | ||
16 | + | let PUBLIC_KEY_HASH_SIZE = 20 | |
17 | + | ||
18 | + | let zeroesStr = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" | |
15 | 19 | ||
16 | 20 | let thisEpochDataKey = "thisEpochData" | |
17 | 21 | ||
30 | 34 | let blockMetaK = "block_0x" | |
31 | 35 | ||
32 | 36 | let finalizedBlockKey = "finalizedBlock" | |
37 | + | ||
38 | + | let tokenIdKey = "tokenId" | |
39 | + | ||
40 | + | let elBridgeAddressKey = "elBridgeAddress" | |
41 | + | ||
42 | + | let prevRandaoHeightKey = "prevRandaoHeight" | |
43 | + | ||
44 | + | let elToClTransfersEpochKey = "elToClTransfersEpoch" | |
33 | 45 | ||
34 | 46 | func pad (i) = { | |
35 | 47 | let s = toString(i) | |
54 | 66 | } | |
55 | 67 | ||
56 | 68 | ||
69 | + | func blockElToClTransfersKey (blockHashHex) = ("elToClTransfers_0x" + blockHashHex) | |
70 | + | ||
71 | + | ||
57 | 72 | func epochMetaKey (epoch) = ("epoch_" + pad(epoch)) | |
58 | 73 | ||
59 | 74 | ||
66 | 81 | func chainLastHeightKey (chainId,miner) = ((("chain_" + pad(chainId)) + "_") + toString(miner)) | |
67 | 82 | ||
68 | 83 | ||
84 | + | func chainForkedHeightKey (chainId) = (("chain_" + pad(chainId)) + "ForkedHeight") | |
85 | + | ||
86 | + | ||
69 | 87 | func supportersKey (chainId) = (("chain" + toString(chainId)) + "Supporters") | |
70 | 88 | ||
71 | 89 | ||
76 | 94 | ||
77 | 95 | ||
78 | 96 | func minerChainIdKey (miner) = (("miner_" + toString(miner)) + "_ChainId") | |
97 | + | ||
98 | + | ||
99 | + | let elToClTransfersEpoch = valueOrElse(getInteger(this, elToClTransfersEpochKey), INT_MAX) | |
100 | + | ||
101 | + | func requireElToClTransfersDisabled () = if ((elToClTransfersEpoch > height)) | |
102 | + | then unit | |
103 | + | else throw((("EL to CL transfers activated on epoch #" + toString(height)) + ". Upgrade your client")) | |
104 | + | ||
105 | + | ||
106 | + | func requireElToClTransfersEnabled () = if ((height >= elToClTransfersEpoch)) | |
107 | + | then unit | |
108 | + | else throw(((("EL to CL transfers haven't activated on epoch #" + toString(height)) + ". Wait for activation on #") + toString(elToClTransfersEpoch))) | |
79 | 109 | ||
80 | 110 | ||
81 | 111 | let stakingContractAddress = match getString(this, stakingContractAddressKey) { | |
111 | 141 | ||
112 | 142 | let mainChainId = valueOrElse(getInteger(mainChainIdKey), 0) | |
113 | 143 | ||
114 | - | let $ | |
144 | + | let $t049114977 = chainMeta(mainChainId) | |
115 | 145 | ||
116 | - | let mainChainHeight = $ | |
146 | + | let mainChainHeight = $t049114977._1 | |
117 | 147 | ||
118 | - | let mainChainLastBlock = $ | |
148 | + | let mainChainLastBlock = $t049114977._2 | |
119 | 149 | ||
120 | 150 | func epochMeta (epoch) = match getString(epochMetaKey(epoch)) { | |
121 | 151 | case s: String => | |
126 | 156 | } | |
127 | 157 | ||
128 | 158 | ||
129 | - | let $ | |
159 | + | let $t052085672 = match epochMeta(height) { | |
130 | 160 | case m: (Address, Int, String) => | |
131 | 161 | m | |
132 | 162 | case _ => | |
142 | 172 | } | |
143 | 173 | } | |
144 | 174 | ||
145 | - | let thisEpochMiner = $ | |
175 | + | let thisEpochMiner = $t052085672._1 | |
146 | 176 | ||
147 | - | let thisEpochRef = $ | |
177 | + | let thisEpochRef = $t052085672._2 | |
148 | 178 | ||
149 | - | let thisEpochLastBlock = $ | |
179 | + | let thisEpochLastBlock = $t052085672._3 | |
150 | 180 | ||
151 | 181 | let allMinersStr = valueOrElse(getString(allMinersKey), "") | |
152 | 182 | ||
167 | 197 | let blockHeight = toInt(meta) | |
168 | 198 | let blockEpoch = toInt(meta, 8) | |
169 | 199 | let blockParent = take(drop(meta, 16), BLOCK_HASH_SIZE) | |
170 | - | let blockGenerator = takeRight(meta, ADDRESS_SIZE) | |
171 | - | $Tuple4(blockHeight, blockEpoch, blockParent, blockGenerator) | |
200 | + | let blockGenerator = take(drop(meta, (16 + BLOCK_HASH_SIZE)), ADDRESS_SIZE) | |
201 | + | if ((elToClTransfersEpoch > blockEpoch)) | |
202 | + | then $Tuple6(blockHeight, blockEpoch, blockParent, blockGenerator, 0, base58'') | |
203 | + | else { | |
204 | + | let chainId = toInt(drop(meta, ((16 + BLOCK_HASH_SIZE) + ADDRESS_SIZE))) | |
205 | + | let elToClTransfersRootHash = drop(meta, ((24 + BLOCK_HASH_SIZE) + ADDRESS_SIZE)) | |
206 | + | $Tuple6(blockHeight, blockEpoch, blockParent, blockGenerator, chainId, elToClTransfersRootHash) | |
207 | + | } | |
208 | + | } | |
209 | + | ||
210 | + | ||
211 | + | func mkBlockMetaEntry (blockHashHex,blockHeight,blockParentHex,blockGenerator,chainId,elToClTransfersRootHashHex) = { | |
212 | + | let blockEpochBytes = toBytes(height) | |
213 | + | let blockMetaBytes = (((((toBytes(blockHeight) + blockEpochBytes) + fromBase16String(blockParentHex)) + blockGenerator.bytes) + toBytes(chainId)) + fromBase16String(elToClTransfersRootHashHex)) | |
214 | + | BinaryEntry((blockMetaK + blockHashHex), blockMetaBytes) | |
172 | 215 | } | |
173 | 216 | ||
174 | 217 | ||
181 | 224 | } | |
182 | 225 | ||
183 | 226 | ||
184 | - | let $ | |
227 | + | let $t073208286 = { | |
185 | 228 | let hitSource = match lastBlock.vrf { | |
186 | 229 | case vrf: ByteVector => | |
187 | 230 | vrf | |
189 | 232 | lastBlock.generationSignature | |
190 | 233 | } | |
191 | 234 | func processMiner (prev,miner) = { | |
192 | - | let $ | |
193 | - | let prevDelay = $ | |
194 | - | let prevMiner = $ | |
195 | - | let prevTotalBalance = $ | |
196 | - | let prevMiners = $ | |
235 | + | let $t076187681 = prev | |
236 | + | let prevDelay = $t076187681._1 | |
237 | + | let prevMiner = $t076187681._2 | |
238 | + | let prevTotalBalance = $t076187681._3 | |
239 | + | let prevMiners = $t076187681._4 | |
197 | 240 | let minerAddress = addressFromStringValue(miner) | |
198 | 241 | let wavesGenBalance = wavesBalance(minerAddress).generating | |
199 | 242 | let minerBalance = generatingBalance(minerAddress) | |
223 | 266 | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50) | |
224 | 267 | } | |
225 | 268 | ||
226 | - | let computedDelay = $ | |
269 | + | let computedDelay = $t073208286._1 | |
227 | 270 | ||
228 | - | let computedGenerator = $ | |
271 | + | let computedGenerator = $t073208286._2 | |
229 | 272 | ||
230 | - | let computedTotalBalance = $ | |
273 | + | let computedTotalBalance = $t073208286._3 | |
231 | 274 | ||
232 | - | let filteredMiners = $ | |
275 | + | let filteredMiners = $t073208286._4 | |
233 | 276 | ||
234 | 277 | func getChainLastBlockId (chainId) = chainMeta(chainId)._2 | |
235 | 278 | ||
236 | 279 | ||
237 | - | let $ | |
280 | + | let $t083528487 = blockMeta(mainChainLastBlock) | |
238 | 281 | ||
239 | - | let | |
282 | + | let mclbIgnored1 = $t083528487._1 | |
240 | 283 | ||
241 | - | let mainChainEpoch = $ | |
284 | + | let mainChainEpoch = $t083528487._2 | |
242 | 285 | ||
243 | - | let mainChainParentHash = $ | |
286 | + | let mainChainParentHash = $t083528487._3 | |
244 | 287 | ||
245 | - | let mainChainGenerator = $t053835485._4 | |
288 | + | let mainChainGenerator = $t083528487._4 | |
289 | + | ||
290 | + | let mclbIgnored2 = $t083528487._5 | |
291 | + | ||
292 | + | let mclbIgnored3 = $t083528487._6 | |
246 | 293 | ||
247 | 294 | func calculateFinalizedBlockHash (curMiner,curPrevEpoch,curLastBlockHash) = { | |
248 | 295 | let offsets_100 = split_4C("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::", "") | |
249 | 296 | let halfBalance = (computedTotalBalance / 2) | |
250 | 297 | func step (prev,next) = { | |
251 | - | let $ | |
252 | - | let thisEpoch = $ | |
253 | - | let totalBalance = $ | |
254 | - | let maybeSafeEpoch = $ | |
255 | - | let prevMiners = $ | |
298 | + | let $t088538917 = prev | |
299 | + | let thisEpoch = $t088538917._1 | |
300 | + | let totalBalance = $t088538917._2 | |
301 | + | let maybeSafeEpoch = $t088538917._3 | |
302 | + | let prevMiners = $t088538917._4 | |
256 | 303 | match maybeSafeEpoch { | |
257 | 304 | case _: Unit => | |
258 | - | let $ | |
305 | + | let $t089759141 = if ((thisEpoch == height)) | |
259 | 306 | then $Tuple3(curMiner, curPrevEpoch, curLastBlockHash) | |
260 | 307 | else value(epochMeta(thisEpoch)) | |
261 | - | let miner = $ | |
262 | - | let prevEpoch = $ | |
263 | - | let lastBlockHash = $ | |
308 | + | let miner = $t089759141._1 | |
309 | + | let prevEpoch = $t089759141._2 | |
310 | + | let lastBlockHash = $t089759141._3 | |
264 | 311 | if ((prevEpoch == 0)) | |
265 | 312 | then $Tuple4(thisEpoch, totalBalance, lastBlockHash, allMiners) | |
266 | 313 | else { | |
267 | - | let $ | |
314 | + | let $t092669468 = if (containsElement(prevMiners, miner)) | |
268 | 315 | then $Tuple2(totalBalance, prevMiners) | |
269 | 316 | else $Tuple2((totalBalance + generatingBalance(miner)), miner :: prevMiners) | |
270 | - | let newTotalBalance = $ | |
271 | - | let newMiners = $ | |
317 | + | let newTotalBalance = $t092669468._1 | |
318 | + | let newMiners = $t092669468._2 | |
272 | 319 | if ((newTotalBalance > halfBalance)) | |
273 | 320 | then $Tuple4(thisEpoch, newTotalBalance, lastBlockHash, allMiners) | |
274 | 321 | else $Tuple4(prevEpoch, newTotalBalance, unit, newMiners) | |
278 | 325 | } | |
279 | 326 | } | |
280 | 327 | ||
281 | - | let $ | |
328 | + | let $t097019834 = { | |
282 | 329 | let $l = (offsets_100 ++ offsets_100) | |
283 | 330 | let $s = size($l) | |
284 | 331 | let $acc0 = $Tuple4(height, 0, unit, nil) | |
292 | 339 | ||
293 | 340 | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100), 101), 102), 103), 104), 105), 106), 107), 108), 109), 110), 111), 112), 113), 114), 115), 116), 117), 118), 119), 120), 121), 122), 123), 124), 125), 126), 127), 128), 129), 130), 131), 132), 133), 134), 135), 136), 137), 138), 139), 140), 141), 142), 143), 144), 145), 146), 147), 148), 149), 150), 151), 152), 153), 154), 155), 156), 157), 158), 159), 160), 161), 162), 163), 164), 165), 166), 167), 168), 169), 170), 171), 172), 173), 174), 175), 176), 177), 178), 179), 180), 181), 182), 183), 184), 185), 186), 187), 188), 189), 190), 191), 192), 193), 194), 195), 196), 197), 198), 199), 200) | |
294 | 341 | } | |
295 | - | let fallbackEpoch = $ | |
296 | - | let totalBalance = $ | |
297 | - | let finalizedBlockHashOpt = $ | |
298 | - | let miners = $ | |
342 | + | let fallbackEpoch = $t097019834._1 | |
343 | + | let totalBalance = $t097019834._2 | |
344 | + | let finalizedBlockHashOpt = $t097019834._3 | |
345 | + | let miners = $t097019834._4 | |
299 | 346 | match finalizedBlockHashOpt { | |
300 | 347 | case finalizedBlockHash: String => | |
301 | 348 | finalizedBlockHash | |
307 | 354 | ||
308 | 355 | func supportingBalance (chainId) = { | |
309 | 356 | func addBalance (acc,generatorStr) = { | |
310 | - | let $ | |
311 | - | let totalBalance = $ | |
312 | - | let generators = $ | |
357 | + | let $t01010410140 = acc | |
358 | + | let totalBalance = $t01010410140._1 | |
359 | + | let generators = $t01010410140._2 | |
313 | 360 | let generator = addressFromStringValue(generatorStr) | |
314 | 361 | if (containsElement(generators, generator)) | |
315 | 362 | then acc | |
320 | 367 | } | |
321 | 368 | ||
322 | 369 | let allGenerators = split_4C(getStringValue(supportersKey(chainId)), SEP) | |
323 | - | let $ | |
370 | + | let $t01046210527 = { | |
324 | 371 | let $l = allGenerators | |
325 | 372 | let $s = size($l) | |
326 | 373 | let $acc0 = $Tuple2(0, nil) | |
334 | 381 | ||
335 | 382 | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100) | |
336 | 383 | } | |
337 | - | let balance = $ | |
338 | - | let _g = $ | |
384 | + | let balance = $t01046210527._1 | |
385 | + | let _g = $t01046210527._2 | |
339 | 386 | balance | |
340 | 387 | } | |
341 | 388 | ||
402 | 449 | } | |
403 | 450 | ||
404 | 451 | ||
452 | + | func setOrFail (flags,index) = if ((0 > index)) | |
453 | + | then throw(("Can't withdraw at negative index: " + toString(index))) | |
454 | + | else { | |
455 | + | let flagsSize = size(flags) | |
456 | + | if ((index >= flagsSize)) | |
457 | + | then { | |
458 | + | let addZeroes = (index - flagsSize) | |
459 | + | if ((addZeroes > size(zeroesStr))) | |
460 | + | then throw((("Can't add " + toString(addZeroes)) + " empty flags. Contact with developers")) | |
461 | + | else ((flags + take(zeroesStr, addZeroes)) + "1") | |
462 | + | } | |
463 | + | else { | |
464 | + | let tail = drop(flags, index) | |
465 | + | let atIndex = take(tail, 1) | |
466 | + | if ((atIndex == "0")) | |
467 | + | then ((take(flags, index) + "1") + drop(tail, 1)) | |
468 | + | else throw((("Transfer #" + toString(index)) + " has been already taken")) | |
469 | + | } | |
470 | + | } | |
471 | + | ||
472 | + | ||
405 | 473 | func validateBlockHash (hexStr) = { | |
406 | 474 | let decodedBytes = fromBase16String(hexStr) | |
407 | 475 | if ((size(decodedBytes) != 32)) | |
413 | 481 | func getUpdateFinalizedBlockAction (caller,newBlockHashHex,prevEpoch) = { | |
414 | 482 | let curFinalizedBlockHeight = blockMeta(getStringValue(finalizedBlockKey))._1 | |
415 | 483 | let newFinalizedBlockHash = calculateFinalizedBlockHash(caller, prevEpoch, newBlockHashHex) | |
416 | - | if ((newFinalizedBlockHash == newBlockHashHex)) | |
484 | + | if (if ((newFinalizedBlockHash == newBlockHashHex)) | |
485 | + | then true | |
486 | + | else (blockMeta(newFinalizedBlockHash)._1 > curFinalizedBlockHeight)) | |
417 | 487 | then [StringEntry(finalizedBlockKey, newFinalizedBlockHash)] | |
418 | - | else if ((blockMeta(newFinalizedBlockHash)._1 > curFinalizedBlockHeight)) | |
419 | - | then [StringEntry(finalizedBlockKey, newFinalizedBlockHash)] | |
420 | - | else nil | |
488 | + | else nil | |
421 | 489 | } | |
422 | 490 | ||
423 | 491 | ||
424 | 492 | @Callable(i) | |
425 | - | func appendBlock (blockHashHex,referenceHex) = if ((thisEpochMiner != i.originCaller)) | |
426 | - | then match thisEpochMiner { | |
427 | - | case epochMiner: Address => | |
428 | - | throw(("not allowed to forge blocks in this epoch, expected from " + toString(epochMiner))) | |
429 | - | case _ => | |
430 | - | throw("not allowed to forge blocks in this epoch, epoch miner is absent") | |
493 | + | func appendBlock (blockHashHex,referenceHex) = { | |
494 | + | let checkVersion = requireElToClTransfersDisabled() | |
495 | + | if ((checkVersion == checkVersion)) | |
496 | + | then if ((thisEpochMiner != i.originCaller)) | |
497 | + | then match thisEpochMiner { | |
498 | + | case epochMiner: Address => | |
499 | + | throw(("not allowed to forge blocks in this epoch, expected from " + toString(epochMiner))) | |
500 | + | case _ => | |
501 | + | throw("not allowed to forge blocks in this epoch, epoch miner is absent") | |
502 | + | } | |
503 | + | else { | |
504 | + | let chainId = valueOrElse(minerChainId(i.originCaller), mainChainId) | |
505 | + | let $t01464414695 = chainMeta(chainId) | |
506 | + | let chainHeight = $t01464414695._1 | |
507 | + | let lastBlockId = $t01464414695._2 | |
508 | + | let checkReference = isReferenceCorrect(referenceHex, lastBlockId) | |
509 | + | if ((checkReference == checkReference)) | |
510 | + | then { | |
511 | + | let newChainHeight = (chainHeight + 1) | |
512 | + | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(lastBlockId)) + i.originCaller.bytes) | |
513 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
514 | + | if ((checkBlockHash == checkBlockHash)) | |
515 | + | then [BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), StringEntry(epochMetaKey(height), ((((toString(value(thisEpochMiner)) + SEP) + toString(thisEpochRef)) + SEP) + blockHashHex))] | |
516 | + | else throw("Strict value is not equal to itself.") | |
517 | + | } | |
518 | + | else throw("Strict value is not equal to itself.") | |
519 | + | } | |
520 | + | else throw("Strict value is not equal to itself.") | |
431 | 521 | } | |
432 | - | else { | |
433 | - | let chainId = valueOrElse(minerChainId(i.originCaller), mainChainId) | |
434 | - | let $t01083310884 = chainMeta(chainId) | |
435 | - | let chainHeight = $t01083310884._1 | |
436 | - | let lastBlockId = $t01083310884._2 | |
437 | - | let checkReference = isReferenceCorrect(referenceHex, lastBlockId) | |
438 | - | if ((checkReference == checkReference)) | |
439 | - | then { | |
440 | - | let newChainHeight = (chainHeight + 1) | |
441 | - | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(lastBlockId)) + i.originCaller.bytes) | |
442 | - | let blockHash = validateBlockHash(blockHashHex) | |
443 | - | [BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), StringEntry(epochMetaKey(height), ((((toString(value(thisEpochMiner)) + SEP) + toString(thisEpochRef)) + SEP) + blockHashHex))] | |
522 | + | ||
523 | + | ||
524 | + | ||
525 | + | @Callable(i) | |
526 | + | func appendBlock_v2 (blockHashHex,referenceHex,elToClTransfersRootHashHex) = { | |
527 | + | let checkVersion = requireElToClTransfersEnabled() | |
528 | + | if ((checkVersion == checkVersion)) | |
529 | + | then if ((thisEpochMiner != i.originCaller)) | |
530 | + | then match thisEpochMiner { | |
531 | + | case epochMiner: Address => | |
532 | + | throw(("not allowed to forge blocks in this epoch, expected from " + toString(epochMiner))) | |
533 | + | case _ => | |
534 | + | throw("not allowed to forge blocks in this epoch, epoch miner is absent") | |
535 | + | } | |
536 | + | else { | |
537 | + | let chainId = valueOrElse(minerChainId(i.originCaller), mainChainId) | |
538 | + | let $t01596916020 = chainMeta(chainId) | |
539 | + | let chainHeight = $t01596916020._1 | |
540 | + | let lastBlockId = $t01596916020._2 | |
541 | + | let checkReference = isReferenceCorrect(referenceHex, lastBlockId) | |
542 | + | if ((checkReference == checkReference)) | |
543 | + | then { | |
544 | + | let newChainHeight = (chainHeight + 1) | |
545 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
546 | + | if ((checkBlockHash == checkBlockHash)) | |
547 | + | then [mkBlockMetaEntry(blockHashHex, newChainHeight, lastBlockId, i.originCaller, chainId, elToClTransfersRootHashHex), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), StringEntry(epochMetaKey(height), ((((toString(value(thisEpochMiner)) + SEP) + toString(thisEpochRef)) + SEP) + blockHashHex))] | |
548 | + | else throw("Strict value is not equal to itself.") | |
549 | + | } | |
550 | + | else throw("Strict value is not equal to itself.") | |
444 | 551 | } | |
445 | - | ||
446 | - | ||
552 | + | else throw("Strict value is not equal to itself.") | |
553 | + | } | |
447 | 554 | ||
448 | 555 | ||
449 | 556 | ||
450 | 557 | @Callable(i) | |
451 | 558 | func extendMainChain (blockHashHex,referenceHex,epoch) = { | |
452 | - | let | |
453 | - | if (( | |
559 | + | let checkVersion = requireElToClTransfersDisabled() | |
560 | + | if ((checkVersion == checkVersion)) | |
454 | 561 | then { | |
455 | - | let | |
456 | - | if (( | |
562 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
563 | + | if ((checkBlockHash == checkBlockHash)) | |
457 | 564 | then { | |
458 | - | let | |
459 | - | if (( | |
565 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
566 | + | if ((checkEpoch == checkEpoch)) | |
460 | 567 | then { | |
461 | - | let | |
462 | - | if (( | |
568 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
569 | + | if ((checkGenerator == checkGenerator)) | |
463 | 570 | then { | |
464 | - | let thisEpochMeta = match epochMeta(height) { | |
465 | - | case _: Unit => | |
466 | - | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(mainChainEpoch)) + SEP) + blockHashHex)) | |
467 | - | case other => | |
468 | - | throw("Epoch already started") | |
571 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, unit) | |
572 | + | if ((checkChain == checkChain)) | |
573 | + | then { | |
574 | + | let checkReference = isReferenceCorrect(referenceHex, mainChainLastBlock) | |
575 | + | if ((checkReference == checkReference)) | |
576 | + | then { | |
577 | + | let thisEpochMeta = match epochMeta(height) { | |
578 | + | case _: Unit => | |
579 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(mainChainEpoch)) + SEP) + blockHashHex)) | |
580 | + | case other => | |
581 | + | throw("Epoch already started") | |
582 | + | } | |
583 | + | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, mainChainEpoch) | |
584 | + | let newChainHeight = (mainChainHeight + 1) | |
585 | + | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(mainChainLastBlock)) + i.originCaller.bytes) | |
586 | + | ([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(mainChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), mainChainId), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), thisEpochMeta] ++ updateFinalizedBlock) | |
587 | + | } | |
588 | + | else throw("Strict value is not equal to itself.") | |
589 | + | } | |
590 | + | else throw("Strict value is not equal to itself.") | |
469 | 591 | } | |
470 | - | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, mainChainEpoch) | |
471 | - | let newChainHeight = (mainChainHeight + 1) | |
472 | - | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(mainChainLastBlock)) + i.originCaller.bytes) | |
473 | - | ([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(mainChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), mainChainId), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), thisEpochMeta] ++ updateFinalizedBlock) | |
592 | + | else throw("Strict value is not equal to itself.") | |
593 | + | } | |
594 | + | else throw("Strict value is not equal to itself.") | |
595 | + | } | |
596 | + | else throw("Strict value is not equal to itself.") | |
597 | + | } | |
598 | + | else throw("Strict value is not equal to itself.") | |
599 | + | } | |
600 | + | ||
601 | + | ||
602 | + | ||
603 | + | @Callable(i) | |
604 | + | func extendMainChain_v2 (blockHashHex,referenceHex,epoch,elToClTransfersRootHashHex) = { | |
605 | + | let checkVersion = requireElToClTransfersEnabled() | |
606 | + | if ((checkVersion == checkVersion)) | |
607 | + | then { | |
608 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
609 | + | if ((checkBlockHash == checkBlockHash)) | |
610 | + | then { | |
611 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
612 | + | if ((checkEpoch == checkEpoch)) | |
613 | + | then { | |
614 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
615 | + | if ((checkGenerator == checkGenerator)) | |
616 | + | then { | |
617 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, unit) | |
618 | + | if ((checkChain == checkChain)) | |
619 | + | then { | |
620 | + | let checkReference = isReferenceCorrect(referenceHex, mainChainLastBlock) | |
621 | + | if ((checkReference == checkReference)) | |
622 | + | then { | |
623 | + | let thisEpochMeta = match epochMeta(height) { | |
624 | + | case _: Unit => | |
625 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(mainChainEpoch)) + SEP) + blockHashHex)) | |
626 | + | case other => | |
627 | + | throw("Epoch already started") | |
628 | + | } | |
629 | + | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, mainChainEpoch) | |
630 | + | let newChainHeight = (mainChainHeight + 1) | |
631 | + | ([mkBlockMetaEntry(blockHashHex, newChainHeight, mainChainLastBlock, i.originCaller, mainChainId, elToClTransfersRootHashHex), StringEntry(chainMetaKey(mainChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), mainChainId), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), thisEpochMeta] ++ updateFinalizedBlock) | |
632 | + | } | |
633 | + | else throw("Strict value is not equal to itself.") | |
634 | + | } | |
635 | + | else throw("Strict value is not equal to itself.") | |
474 | 636 | } | |
475 | 637 | else throw("Strict value is not equal to itself.") | |
476 | 638 | } | |
485 | 647 | ||
486 | 648 | @Callable(i) | |
487 | 649 | func startAltChain (blockHashHex,referenceHex,epoch) = { | |
488 | - | let | |
489 | - | if (( | |
650 | + | let checkVersion = requireElToClTransfersDisabled() | |
651 | + | if ((checkVersion == checkVersion)) | |
490 | 652 | then { | |
491 | - | let | |
492 | - | if (( | |
653 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
654 | + | if ((checkBlockHash == checkBlockHash)) | |
493 | 655 | then { | |
494 | - | let $t01309313171 = blockMeta(referenceHex) | |
495 | - | let refChainHeight = $t01309313171._1 | |
496 | - | let refEpoch = $t01309313171._2 | |
497 | - | let refRef = $t01309313171._3 | |
498 | - | let refGenerator = $t01309313171._4 | |
499 | - | let finalizedEpoch = blockMeta(getStringValue(finalizedBlockKey))._2 | |
500 | - | let epochRef = if ((refEpoch >= finalizedEpoch)) | |
501 | - | then refEpoch | |
502 | - | else throw((((("can not start alt chain from epoch " + toString(refEpoch)) + ", epoch ") + toString(finalizedEpoch)) + " is finalized")) | |
503 | - | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, referenceHex) | |
504 | - | if ((checkChain == checkChain)) | |
656 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
657 | + | if ((checkEpoch == checkEpoch)) | |
505 | 658 | then { | |
506 | - | let newChainId = (valueOrElse(getInteger(lastChainIdKey), 0) + 1) | |
507 | - | let referenceHeight = blockMeta(referenceHex)._1 | |
508 | - | let newChainHeight = (referenceHeight + 1) | |
509 | - | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(referenceHex)) + i.originCaller.bytes) | |
510 | - | let thisEpochMeta = match epochMeta(height) { | |
511 | - | case _: Unit => | |
512 | - | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(epochRef)) + SEP) + blockHashHex)) | |
513 | - | case other => | |
514 | - | throw("Epoch already started") | |
659 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
660 | + | if ((checkGenerator == checkGenerator)) | |
661 | + | then { | |
662 | + | let $t01969819802 = blockMeta(referenceHex) | |
663 | + | let refChainHeight = $t01969819802._1 | |
664 | + | let refEpoch = $t01969819802._2 | |
665 | + | let refRef = $t01969819802._3 | |
666 | + | let refGenerator = $t01969819802._4 | |
667 | + | let refIgnored1 = $t01969819802._5 | |
668 | + | let refIgnored2 = $t01969819802._6 | |
669 | + | let finalizedEpoch = blockMeta(getStringValue(finalizedBlockKey))._2 | |
670 | + | let epochRef = if ((refEpoch >= finalizedEpoch)) | |
671 | + | then refEpoch | |
672 | + | else throw((((("can not start alt chain from epoch " + toString(refEpoch)) + ", epoch ") + toString(finalizedEpoch)) + " is finalized")) | |
673 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, referenceHex) | |
674 | + | if ((checkChain == checkChain)) | |
675 | + | then { | |
676 | + | let newChainId = (valueOrElse(getInteger(lastChainIdKey), 0) + 1) | |
677 | + | let newChainHeight = (blockMeta(referenceHex)._1 + 1) | |
678 | + | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(referenceHex)) + i.originCaller.bytes) | |
679 | + | let thisEpochMeta = match epochMeta(height) { | |
680 | + | case _: Unit => | |
681 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(epochRef)) + SEP) + blockHashHex)) | |
682 | + | case other => | |
683 | + | throw("Epoch already started") | |
684 | + | } | |
685 | + | [thisEpochMeta, BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainFirstBlockIdKey(newChainId), blockHashHex), StringEntry(chainMetaKey(newChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), newChainId), IntegerEntry(chainLastHeightKey(newChainId, i.originCaller), newChainHeight), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), StringEntry(supportersKey(newChainId), toString(i.originCaller)), IntegerEntry(lastChainIdKey, newChainId)] | |
686 | + | } | |
687 | + | else throw("Strict value is not equal to itself.") | |
688 | + | } | |
689 | + | else throw("Strict value is not equal to itself.") | |
515 | 690 | } | |
516 | - | [thisEpochMeta, BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainFirstBlockIdKey(newChainId), blockHashHex), StringEntry(chainMetaKey(newChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), newChainId), IntegerEntry(chainLastHeightKey(newChainId, i.originCaller), newChainHeight), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), referenceHeight), StringEntry(supportersKey(newChainId), toString(i.originCaller)), IntegerEntry(lastChainIdKey, newChainId)] | |
691 | + | else throw("Strict value is not equal to itself.") | |
692 | + | } | |
693 | + | else throw("Strict value is not equal to itself.") | |
694 | + | } | |
695 | + | else throw("Strict value is not equal to itself.") | |
696 | + | } | |
697 | + | ||
698 | + | ||
699 | + | ||
700 | + | @Callable(i) | |
701 | + | func startAltChain_v2 (blockHashHex,referenceHex,epoch,elToClTransfersRootHashHex) = { | |
702 | + | let checkVersion = requireElToClTransfersEnabled() | |
703 | + | if ((checkVersion == checkVersion)) | |
704 | + | then { | |
705 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
706 | + | if ((checkBlockHash == checkBlockHash)) | |
707 | + | then { | |
708 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
709 | + | if ((checkEpoch == checkEpoch)) | |
710 | + | then { | |
711 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
712 | + | if ((checkGenerator == checkGenerator)) | |
713 | + | then { | |
714 | + | let $t02161221716 = blockMeta(referenceHex) | |
715 | + | let refChainHeight = $t02161221716._1 | |
716 | + | let refEpoch = $t02161221716._2 | |
717 | + | let refRef = $t02161221716._3 | |
718 | + | let refGenerator = $t02161221716._4 | |
719 | + | let refIgnored1 = $t02161221716._5 | |
720 | + | let refIgnored2 = $t02161221716._6 | |
721 | + | let finalizedEpoch = blockMeta(getStringValue(finalizedBlockKey))._2 | |
722 | + | let epochRef = if ((refEpoch >= finalizedEpoch)) | |
723 | + | then refEpoch | |
724 | + | else throw((((("can not start alt chain from epoch " + toString(refEpoch)) + ", epoch ") + toString(finalizedEpoch)) + " is finalized")) | |
725 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, referenceHex) | |
726 | + | if ((checkChain == checkChain)) | |
727 | + | then { | |
728 | + | let newChainId = (valueOrElse(getInteger(lastChainIdKey), 0) + 1) | |
729 | + | let newChainHeight = (blockMeta(referenceHex)._1 + 1) | |
730 | + | let thisEpochMeta = match epochMeta(height) { | |
731 | + | case _: Unit => | |
732 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(epochRef)) + SEP) + blockHashHex)) | |
733 | + | case other => | |
734 | + | throw("Epoch already started") | |
735 | + | } | |
736 | + | [thisEpochMeta, mkBlockMetaEntry(blockHashHex, newChainHeight, referenceHex, i.originCaller, newChainId, elToClTransfersRootHashHex), StringEntry(chainFirstBlockIdKey(newChainId), blockHashHex), StringEntry(chainMetaKey(newChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), newChainId), IntegerEntry(chainLastHeightKey(newChainId, i.originCaller), newChainHeight), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), StringEntry(supportersKey(newChainId), toString(i.originCaller)), IntegerEntry(lastChainIdKey, newChainId)] | |
737 | + | } | |
738 | + | else throw("Strict value is not equal to itself.") | |
739 | + | } | |
740 | + | else throw("Strict value is not equal to itself.") | |
517 | 741 | } | |
518 | 742 | else throw("Strict value is not equal to itself.") | |
519 | 743 | } | |
526 | 750 | ||
527 | 751 | @Callable(i) | |
528 | 752 | func extendAltChain (chainId,blockHashHex,referenceHex,epoch) = { | |
529 | - | let | |
530 | - | if (( | |
753 | + | let checkVersion = requireElToClTransfersDisabled() | |
754 | + | if ((checkVersion == checkVersion)) | |
531 | 755 | then { | |
532 | - | let | |
533 | - | if (( | |
756 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
757 | + | if ((checkBlockHash == checkBlockHash)) | |
534 | 758 | then { | |
535 | - | let | |
536 | - | if (( | |
759 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
760 | + | if ((checkEpoch == checkEpoch)) | |
537 | 761 | then { | |
538 | - | let $t01534015394 = chainMeta(chainId) | |
539 | - | let chainHeight = $t01534015394._1 | |
540 | - | let chainLastBlock = $t01534015394._2 | |
541 | - | let checkReference = isReferenceCorrect(referenceHex, chainLastBlock) | |
542 | - | if ((checkReference == checkReference)) | |
762 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
763 | + | if ((checkGenerator == checkGenerator)) | |
543 | 764 | then { | |
544 | - | let | |
545 | - | let | |
546 | - | | |
765 | + | let chainFirstBlockMeta = blockMeta(getStringValue(chainFirstBlockIdKey(chainId))) | |
766 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, chainId, toBase16String(chainFirstBlockMeta._3)) | |
767 | + | if ((checkChain == checkChain)) | |
547 | 768 | then { | |
548 | - | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, prevEpoch) | |
549 | - | ([IntegerEntry(mainChainIdKey, chainId), IntegerEntry(firstValidAltChainIdKey, (valueOrElse(getInteger(lastChainIdKey), 0) + 1))] ++ updateFinalizedBlock) | |
769 | + | let $t02395524009 = chainMeta(chainId) | |
770 | + | let chainHeight = $t02395524009._1 | |
771 | + | let chainLastBlock = $t02395524009._2 | |
772 | + | let checkReference = isReferenceCorrect(referenceHex, chainLastBlock) | |
773 | + | if ((checkReference == checkReference)) | |
774 | + | then { | |
775 | + | let newChainHeight = (chainHeight + 1) | |
776 | + | let prevEpoch = blockMeta(referenceHex)._2 | |
777 | + | let updateMainChainData = if ((supportingBalance(chainId) > (computedTotalBalance / 2))) | |
778 | + | then { | |
779 | + | let lastChainId = valueOrElse(getInteger(lastChainIdKey), 0) | |
780 | + | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, prevEpoch) | |
781 | + | ([IntegerEntry(chainForkedHeightKey(mainChainId), chainFirstBlockMeta._1), IntegerEntry(mainChainIdKey, chainId), IntegerEntry(firstValidAltChainIdKey, (lastChainId + 1))] ++ updateFinalizedBlock) | |
782 | + | } | |
783 | + | else nil | |
784 | + | let thisEpochMeta = match epochMeta(height) { | |
785 | + | case _: Unit => | |
786 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(prevEpoch)) + SEP) + blockHashHex)) | |
787 | + | case other => | |
788 | + | throw("Epoch already started") | |
789 | + | } | |
790 | + | let updateMainChainLastMinedBlock = if (if ((updateMainChainData == nil)) | |
791 | + | then (valueOrElse(minerChainId(i.originCaller), 0) != chainId) | |
792 | + | else false) | |
793 | + | then [IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), chainFirstBlockMeta._1)] | |
794 | + | else nil | |
795 | + | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(referenceHex)) + i.originCaller.bytes) | |
796 | + | ((([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), thisEpochMeta, IntegerEntry(minerChainIdKey(i.originCaller), chainId), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight)] ++ updateMainChainData) ++ addSupporter(chainId, i.originCaller)) ++ updateMainChainLastMinedBlock) | |
797 | + | } | |
798 | + | else throw("Strict value is not equal to itself.") | |
550 | 799 | } | |
551 | - | else nil | |
552 | - | let thisEpochMeta = match epochMeta(height) { | |
553 | - | case _: Unit => | |
554 | - | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(prevEpoch)) + SEP) + blockHashHex)) | |
555 | - | case other => | |
556 | - | throw("Epoch already started") | |
800 | + | else throw("Strict value is not equal to itself.") | |
557 | 801 | } | |
558 | - | let updateMainChainLastMinedBlock = if (if ((updateMainChainData == nil)) | |
559 | - | then (valueOrElse(minerChainId(i.originCaller), 0) != chainId) | |
560 | - | else false) | |
561 | - | then [IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), blockMeta(getStringValue(chainFirstBlockIdKey(chainId)))._1)] | |
562 | - | else nil | |
563 | - | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(referenceHex)) + i.originCaller.bytes) | |
564 | - | ((([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), thisEpochMeta, IntegerEntry(minerChainIdKey(i.originCaller), chainId), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight)] ++ updateMainChainData) ++ addSupporter(chainId, i.originCaller)) ++ updateMainChainLastMinedBlock) | |
802 | + | else throw("Strict value is not equal to itself.") | |
803 | + | } | |
804 | + | else throw("Strict value is not equal to itself.") | |
805 | + | } | |
806 | + | else throw("Strict value is not equal to itself.") | |
807 | + | } | |
808 | + | else throw("Strict value is not equal to itself.") | |
809 | + | } | |
810 | + | ||
811 | + | ||
812 | + | ||
813 | + | @Callable(i) | |
814 | + | func extendAltChain_v2 (chainId,blockHashHex,referenceHex,epoch,elToClTransfersRootHashHex) = { | |
815 | + | let checkVersion = requireElToClTransfersEnabled() | |
816 | + | if ((checkVersion == checkVersion)) | |
817 | + | then { | |
818 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
819 | + | if ((checkBlockHash == checkBlockHash)) | |
820 | + | then { | |
821 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
822 | + | if ((checkEpoch == checkEpoch)) | |
823 | + | then { | |
824 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
825 | + | if ((checkGenerator == checkGenerator)) | |
826 | + | then { | |
827 | + | let chainFirstBlockMeta = blockMeta(getStringValue(chainFirstBlockIdKey(chainId))) | |
828 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, chainId, toBase16String(chainFirstBlockMeta._3)) | |
829 | + | if ((checkChain == checkChain)) | |
830 | + | then { | |
831 | + | let $t02661226666 = chainMeta(chainId) | |
832 | + | let chainHeight = $t02661226666._1 | |
833 | + | let chainLastBlock = $t02661226666._2 | |
834 | + | let checkReference = isReferenceCorrect(referenceHex, chainLastBlock) | |
835 | + | if ((checkReference == checkReference)) | |
836 | + | then { | |
837 | + | let newChainHeight = (chainHeight + 1) | |
838 | + | let prevEpoch = blockMeta(referenceHex)._2 | |
839 | + | let updateMainChainData = if ((supportingBalance(chainId) > (computedTotalBalance / 2))) | |
840 | + | then { | |
841 | + | let lastChainId = valueOrElse(getInteger(lastChainIdKey), 0) | |
842 | + | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, prevEpoch) | |
843 | + | ([IntegerEntry(chainForkedHeightKey(mainChainId), chainFirstBlockMeta._1), IntegerEntry(mainChainIdKey, chainId), IntegerEntry(firstValidAltChainIdKey, (lastChainId + 1))] ++ updateFinalizedBlock) | |
844 | + | } | |
845 | + | else nil | |
846 | + | let thisEpochMeta = match epochMeta(height) { | |
847 | + | case _: Unit => | |
848 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(prevEpoch)) + SEP) + blockHashHex)) | |
849 | + | case other => | |
850 | + | throw("Epoch already started") | |
851 | + | } | |
852 | + | let updateMainChainLastMinedBlock = if (if ((updateMainChainData == nil)) | |
853 | + | then (valueOrElse(minerChainId(i.originCaller), 0) != chainId) | |
854 | + | else false) | |
855 | + | then [IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), chainFirstBlockMeta._1)] | |
856 | + | else nil | |
857 | + | ((([mkBlockMetaEntry(blockHashHex, newChainHeight, referenceHex, i.originCaller, chainId, elToClTransfersRootHashHex), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), thisEpochMeta, IntegerEntry(minerChainIdKey(i.originCaller), chainId), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight)] ++ updateMainChainData) ++ addSupporter(chainId, i.originCaller)) ++ updateMainChainLastMinedBlock) | |
858 | + | } | |
859 | + | else throw("Strict value is not equal to itself.") | |
860 | + | } | |
861 | + | else throw("Strict value is not equal to itself.") | |
565 | 862 | } | |
566 | 863 | else throw("Strict value is not equal to itself.") | |
567 | 864 | } | |
671 | 968 | ||
672 | 969 | ||
673 | 970 | @Callable(i) | |
674 | - | func setup (genesisBlockHashHex,minerReward,stakingContractAddressB58) = if (isContractSetup()) | |
971 | + | func withdraw (blockHashHex,merkleProof,transferIndexInBlock,amount) = { | |
972 | + | let checkActivation = requireElToClTransfersEnabled() | |
973 | + | if ((checkActivation == checkActivation)) | |
974 | + | then { | |
975 | + | let withdrawBlockMeta = blockMeta(blockHashHex) | |
976 | + | let withdrawBlockHeight = withdrawBlockMeta._1 | |
977 | + | let finalizedBlockHeight = blockMeta(getStringValue(finalizedBlockKey))._1 | |
978 | + | let mainChainLastBlockHeight = blockMeta(mainChainLastBlock)._1 | |
979 | + | if ((withdrawBlockHeight > finalizedBlockHeight)) | |
980 | + | then throw(((("EL block #" + toString(withdrawBlockHeight)) + " is not finalized. The current finalized is #") + toString(finalizedBlockHeight))) | |
981 | + | else { | |
982 | + | let withdrawBlockChainId = withdrawBlockMeta._5 | |
983 | + | let isMainChain = (withdrawBlockChainId == mainChainId) | |
984 | + | let relatesToMainChain = match getInteger(chainForkedHeightKey(withdrawBlockChainId)) { | |
985 | + | case forkedHeight: Int => | |
986 | + | (forkedHeight > withdrawBlockHeight) | |
987 | + | case _ => | |
988 | + | throw((((blockHashHex + " is on an alternative chain #") + toString(withdrawBlockChainId)) + " that was not approved by majority. Wait for some blocks")) | |
989 | + | } | |
990 | + | if (if (isMainChain) | |
991 | + | then true | |
992 | + | else relatesToMainChain) | |
993 | + | then { | |
994 | + | let recipient = i.originCaller | |
995 | + | let recipientPkHash = take(drop(recipient.bytes, 2), PUBLIC_KEY_HASH_SIZE) | |
996 | + | let zeroAmountBytes = base58'11111111111111111111111111111111111111111111' | |
997 | + | let amountBytes = toBytes(amount) | |
998 | + | let elEventData = ((recipientPkHash + take(zeroAmountBytes, (size(zeroAmountBytes) - size(amountBytes)))) + amountBytes) | |
999 | + | let elEventDataDigest = blake2b256_16Kb(elEventData) | |
1000 | + | let calculatedRootHash = createMerkleRoot(merkleProof, elEventDataDigest, transferIndexInBlock) | |
1001 | + | let expectedRootHash = withdrawBlockMeta._6 | |
1002 | + | if ((calculatedRootHash == expectedRootHash)) | |
1003 | + | then { | |
1004 | + | let tokenId = fromBase58String(getStringValue(tokenIdKey)) | |
1005 | + | let transfersKey = blockElToClTransfersKey(blockHashHex) | |
1006 | + | [Reissue(tokenId, amount, true), ScriptTransfer(recipient, amount, tokenId), StringEntry(transfersKey, setOrFail(valueOrElse(getString(transfersKey), ""), transferIndexInBlock))] | |
1007 | + | } | |
1008 | + | else throw(((((("Expected root hash: " + toBase16String(expectedRootHash)) + ", got: ") + toBase16String(calculatedRootHash)) + ". Event data digest: ") + toBase64String(elEventDataDigest))) | |
1009 | + | } | |
1010 | + | else throw((("Expected " + blockHashHex) + " to be either on the main chain or relate to it")) | |
1011 | + | } | |
1012 | + | } | |
1013 | + | else throw("Strict value is not equal to itself.") | |
1014 | + | } | |
1015 | + | ||
1016 | + | ||
1017 | + | ||
1018 | + | @Callable(i) | |
1019 | + | func setup (genesisBlockHashHex,minerRewardInGwei,stakingContractAddressB58,elBridgeAddressHex) = if (isContractSetup()) | |
675 | 1020 | then throw("The contract has been already set up") | |
1021 | + | else if ((0 > minerRewardInGwei)) | |
1022 | + | then throw("The miner reward must be nonnegative") | |
1023 | + | else { | |
1024 | + | let genesisBlockHash = fromBase16String(genesisBlockHashHex) | |
1025 | + | let emptyPk = base58'11111111111111111111111111111111' | |
1026 | + | let genesisMinerAddress = addressFromPublicKey(emptyPk) | |
1027 | + | let genesisEthRewardAddress = base58'11111111111111111111' | |
1028 | + | let genesisBlockReferenceHash = "0000000000000000000000000000000000000000000000000000000000000000" | |
1029 | + | let issue = Issue("UNIT0", "Native token", 0, 8, true) | |
1030 | + | let tokenId = calculateAssetId(issue) | |
1031 | + | [mkBlockMetaEntry(genesisBlockHashHex, 0, genesisBlockReferenceHash, genesisMinerAddress, mainChainId, ""), StringEntry(chainFirstBlockIdKey(0), genesisBlockHashHex), StringEntry(chainMetaKey(0), ("0," + genesisBlockHashHex)), IntegerEntry(minerRewardKey, minerRewardInGwei), StringEntry(stakingContractAddressKey, stakingContractAddressB58), StringEntry(epochMetaKey(height), ((toString(genesisMinerAddress) + ",0,") + genesisBlockHashHex)), StringEntry(finalizedBlockKey, genesisBlockHashHex), IntegerEntry(prevRandaoHeightKey, 0), IntegerEntry(elToClTransfersEpochKey, 0), issue, StringEntry(tokenIdKey, toBase58String(tokenId)), StringEntry(elBridgeAddressKey, ("0x" + elBridgeAddressHex))] | |
1032 | + | } | |
1033 | + | ||
1034 | + | ||
1035 | + | ||
1036 | + | @Callable(i) | |
1037 | + | func setupElToClTransfers (activationHeight,elBridgeAddressHex) = if (isDefined(getInteger(elToClTransfersEpochKey))) | |
1038 | + | then throw("EL to CL transfers feature was set up") | |
676 | 1039 | else { | |
677 | - | let genesisBlockHash = fromBase16String(genesisBlockHashHex) | |
678 | - | let emptyPk = base58'11111111111111111111111111111111' | |
679 | - | let genesisMinerAddress = addressFromPublicKey(emptyPk) | |
680 | - | let genesisEthRewardAddress = base58'11111111111111111111' | |
681 | - | let genesisBlockReferenceHash = base58'11111111111111111111111111111111' | |
682 | - | let genesisBlockMeta = (((toBytes(0) + toBytes(height)) + genesisBlockReferenceHash) + genesisMinerAddress.bytes) | |
683 | - | [BinaryEntry((blockMetaK + genesisBlockHashHex), genesisBlockMeta), StringEntry(chainFirstBlockIdKey(0), genesisBlockHashHex), StringEntry(chainMetaKey(0), ("0," + genesisBlockHashHex)), IntegerEntry(minerRewardKey, minerReward), StringEntry(stakingContractAddressKey, stakingContractAddressB58), StringEntry(epochMetaKey(height), ((toString(genesisMinerAddress) + ",0,") + genesisBlockHashHex)), StringEntry(finalizedBlockKey, genesisBlockHashHex)] | |
1040 | + | let issue = Issue("UNIT0", "Native token", 0, 8, true) | |
1041 | + | let tokenId = calculateAssetId(issue) | |
1042 | + | [IntegerEntry(elToClTransfersEpochKey, activationHeight), issue, StringEntry(tokenIdKey, toBase58String(tokenId)), StringEntry(elBridgeAddressKey, ("0x" + elBridgeAddressHex))] | |
684 | 1043 | } | |
685 | 1044 | ||
686 | 1045 |
Old | New | Differences | |
---|---|---|---|
1 | 1 | {-# STDLIB_VERSION 8 #-} | |
2 | 2 | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | 3 | {-# CONTENT_TYPE DAPP #-} | |
4 | 4 | let INT_MAX = 9223372036854775807 | |
5 | 5 | ||
6 | 6 | let WAVES = 100000000 | |
7 | 7 | ||
8 | 8 | let MIN_BALANCE = (20000 * WAVES) | |
9 | 9 | ||
10 | 10 | let SEP = "," | |
11 | 11 | ||
12 | 12 | let BLOCK_HASH_SIZE = 32 | |
13 | 13 | ||
14 | 14 | let ADDRESS_SIZE = 26 | |
15 | + | ||
16 | + | let PUBLIC_KEY_HASH_SIZE = 20 | |
17 | + | ||
18 | + | let zeroesStr = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" | |
15 | 19 | ||
16 | 20 | let thisEpochDataKey = "thisEpochData" | |
17 | 21 | ||
18 | 22 | let allMinersKey = "allMiners" | |
19 | 23 | ||
20 | 24 | let mainChainIdKey = "mainChainId" | |
21 | 25 | ||
22 | 26 | let lastChainIdKey = "lastChainId" | |
23 | 27 | ||
24 | 28 | let firstValidAltChainIdKey = "firstValidAltChainId" | |
25 | 29 | ||
26 | 30 | let minerRewardKey = "minerReward" | |
27 | 31 | ||
28 | 32 | let stakingContractAddressKey = "stakingContractAddress" | |
29 | 33 | ||
30 | 34 | let blockMetaK = "block_0x" | |
31 | 35 | ||
32 | 36 | let finalizedBlockKey = "finalizedBlock" | |
37 | + | ||
38 | + | let tokenIdKey = "tokenId" | |
39 | + | ||
40 | + | let elBridgeAddressKey = "elBridgeAddress" | |
41 | + | ||
42 | + | let prevRandaoHeightKey = "prevRandaoHeight" | |
43 | + | ||
44 | + | let elToClTransfersEpochKey = "elToClTransfersEpoch" | |
33 | 45 | ||
34 | 46 | func pad (i) = { | |
35 | 47 | let s = toString(i) | |
36 | 48 | match size(s) { | |
37 | 49 | case _ => | |
38 | 50 | if ((1 == $match0)) | |
39 | 51 | then ("0000000" + s) | |
40 | 52 | else if ((2 == $match0)) | |
41 | 53 | then ("000000" + s) | |
42 | 54 | else if ((3 == $match0)) | |
43 | 55 | then ("00000" + s) | |
44 | 56 | else if ((4 == $match0)) | |
45 | 57 | then ("0000" + s) | |
46 | 58 | else if ((5 == $match0)) | |
47 | 59 | then ("000" + s) | |
48 | 60 | else if ((6 == $match0)) | |
49 | 61 | then ("00" + s) | |
50 | 62 | else if ((7 == $match0)) | |
51 | 63 | then ("0" + s) | |
52 | 64 | else s | |
53 | 65 | } | |
54 | 66 | } | |
55 | 67 | ||
56 | 68 | ||
69 | + | func blockElToClTransfersKey (blockHashHex) = ("elToClTransfers_0x" + blockHashHex) | |
70 | + | ||
71 | + | ||
57 | 72 | func epochMetaKey (epoch) = ("epoch_" + pad(epoch)) | |
58 | 73 | ||
59 | 74 | ||
60 | 75 | func chainFirstBlockIdKey (chainId) = (("chain" + toString(chainId)) + "FirstBlock") | |
61 | 76 | ||
62 | 77 | ||
63 | 78 | func chainMetaKey (chainId) = ("chain_" + pad(chainId)) | |
64 | 79 | ||
65 | 80 | ||
66 | 81 | func chainLastHeightKey (chainId,miner) = ((("chain_" + pad(chainId)) + "_") + toString(miner)) | |
67 | 82 | ||
68 | 83 | ||
84 | + | func chainForkedHeightKey (chainId) = (("chain_" + pad(chainId)) + "ForkedHeight") | |
85 | + | ||
86 | + | ||
69 | 87 | func supportersKey (chainId) = (("chain" + toString(chainId)) + "Supporters") | |
70 | 88 | ||
71 | 89 | ||
72 | 90 | func minerRewardAddressKey (minerAddr) = (("miner_" + minerAddr) + "_RewardAddress") | |
73 | 91 | ||
74 | 92 | ||
75 | 93 | func minerPkKey (rewardAddress) = (("miner_0x" + rewardAddress) + "_PK") | |
76 | 94 | ||
77 | 95 | ||
78 | 96 | func minerChainIdKey (miner) = (("miner_" + toString(miner)) + "_ChainId") | |
97 | + | ||
98 | + | ||
99 | + | let elToClTransfersEpoch = valueOrElse(getInteger(this, elToClTransfersEpochKey), INT_MAX) | |
100 | + | ||
101 | + | func requireElToClTransfersDisabled () = if ((elToClTransfersEpoch > height)) | |
102 | + | then unit | |
103 | + | else throw((("EL to CL transfers activated on epoch #" + toString(height)) + ". Upgrade your client")) | |
104 | + | ||
105 | + | ||
106 | + | func requireElToClTransfersEnabled () = if ((height >= elToClTransfersEpoch)) | |
107 | + | then unit | |
108 | + | else throw(((("EL to CL transfers haven't activated on epoch #" + toString(height)) + ". Wait for activation on #") + toString(elToClTransfersEpoch))) | |
79 | 109 | ||
80 | 110 | ||
81 | 111 | let stakingContractAddress = match getString(this, stakingContractAddressKey) { | |
82 | 112 | case s: String => | |
83 | 113 | valueOrErrorMessage(addressFromString(s), ("invalid staking contract address: " + s)) | |
84 | 114 | case _ => | |
85 | 115 | Address(getBinaryValue(this, stakingContractAddressKey)) | |
86 | 116 | } | |
87 | 117 | ||
88 | 118 | func generatingBalance (address) = match getString(stakingContractAddress, ("%s__" + toString(address))) { | |
89 | 119 | case str: String => | |
90 | 120 | let paramList = split(str, "__") | |
91 | 121 | let prevHeight = parseIntValue(paramList[1]) | |
92 | 122 | let prevBalance = parseIntValue(paramList[2]) | |
93 | 123 | let nextHeight = parseIntValue(paramList[3]) | |
94 | 124 | let nextBalance = parseIntValue(paramList[4]) | |
95 | 125 | if ((height >= nextHeight)) | |
96 | 126 | then nextBalance | |
97 | 127 | else if ((height >= prevHeight)) | |
98 | 128 | then prevBalance | |
99 | 129 | else 0 | |
100 | 130 | case _ => | |
101 | 131 | 0 | |
102 | 132 | } | |
103 | 133 | ||
104 | 134 | ||
105 | 135 | func chainMeta (chainId) = { | |
106 | 136 | let s = getStringValue(chainMetaKey(chainId)) | |
107 | 137 | let items = split(s, SEP) | |
108 | 138 | $Tuple2(parseIntValue(items[0]), items[1]) | |
109 | 139 | } | |
110 | 140 | ||
111 | 141 | ||
112 | 142 | let mainChainId = valueOrElse(getInteger(mainChainIdKey), 0) | |
113 | 143 | ||
114 | - | let $ | |
144 | + | let $t049114977 = chainMeta(mainChainId) | |
115 | 145 | ||
116 | - | let mainChainHeight = $ | |
146 | + | let mainChainHeight = $t049114977._1 | |
117 | 147 | ||
118 | - | let mainChainLastBlock = $ | |
148 | + | let mainChainLastBlock = $t049114977._2 | |
119 | 149 | ||
120 | 150 | func epochMeta (epoch) = match getString(epochMetaKey(epoch)) { | |
121 | 151 | case s: String => | |
122 | 152 | let fragments = split(s, SEP) | |
123 | 153 | $Tuple3(addressFromStringValue(fragments[0]), parseIntValue(fragments[1]), fragments[2]) | |
124 | 154 | case _ => | |
125 | 155 | unit | |
126 | 156 | } | |
127 | 157 | ||
128 | 158 | ||
129 | - | let $ | |
159 | + | let $t052085672 = match epochMeta(height) { | |
130 | 160 | case m: (Address, Int, String) => | |
131 | 161 | m | |
132 | 162 | case _ => | |
133 | 163 | match getString(thisEpochDataKey) { | |
134 | 164 | case rawThisEpochData: String => | |
135 | 165 | let thisEpochData = split(rawThisEpochData, SEP) | |
136 | 166 | let thisEpoch = parseIntValue(thisEpochData[0]) | |
137 | 167 | $Tuple3(if ((thisEpoch == height)) | |
138 | 168 | then addressFromStringValue(thisEpochData[1]) | |
139 | 169 | else unit, 0, "") | |
140 | 170 | case _ => | |
141 | 171 | $Tuple3(unit, 0, "") | |
142 | 172 | } | |
143 | 173 | } | |
144 | 174 | ||
145 | - | let thisEpochMiner = $ | |
175 | + | let thisEpochMiner = $t052085672._1 | |
146 | 176 | ||
147 | - | let thisEpochRef = $ | |
177 | + | let thisEpochRef = $t052085672._2 | |
148 | 178 | ||
149 | - | let thisEpochLastBlock = $ | |
179 | + | let thisEpochLastBlock = $t052085672._3 | |
150 | 180 | ||
151 | 181 | let allMinersStr = valueOrElse(getString(allMinersKey), "") | |
152 | 182 | ||
153 | 183 | let allMiners = match allMinersStr { | |
154 | 184 | case _ => | |
155 | 185 | if (("" == $match0)) | |
156 | 186 | then nil | |
157 | 187 | else if ($isInstanceOf($match0, "String")) | |
158 | 188 | then { | |
159 | 189 | let raw = $match0 | |
160 | 190 | split_4C(raw, SEP) | |
161 | 191 | } | |
162 | 192 | else throw("Match error") | |
163 | 193 | } | |
164 | 194 | ||
165 | 195 | func blockMeta (blockId) = { | |
166 | 196 | let meta = getBinaryValue((blockMetaK + blockId)) | |
167 | 197 | let blockHeight = toInt(meta) | |
168 | 198 | let blockEpoch = toInt(meta, 8) | |
169 | 199 | let blockParent = take(drop(meta, 16), BLOCK_HASH_SIZE) | |
170 | - | let blockGenerator = takeRight(meta, ADDRESS_SIZE) | |
171 | - | $Tuple4(blockHeight, blockEpoch, blockParent, blockGenerator) | |
200 | + | let blockGenerator = take(drop(meta, (16 + BLOCK_HASH_SIZE)), ADDRESS_SIZE) | |
201 | + | if ((elToClTransfersEpoch > blockEpoch)) | |
202 | + | then $Tuple6(blockHeight, blockEpoch, blockParent, blockGenerator, 0, base58'') | |
203 | + | else { | |
204 | + | let chainId = toInt(drop(meta, ((16 + BLOCK_HASH_SIZE) + ADDRESS_SIZE))) | |
205 | + | let elToClTransfersRootHash = drop(meta, ((24 + BLOCK_HASH_SIZE) + ADDRESS_SIZE)) | |
206 | + | $Tuple6(blockHeight, blockEpoch, blockParent, blockGenerator, chainId, elToClTransfersRootHash) | |
207 | + | } | |
208 | + | } | |
209 | + | ||
210 | + | ||
211 | + | func mkBlockMetaEntry (blockHashHex,blockHeight,blockParentHex,blockGenerator,chainId,elToClTransfersRootHashHex) = { | |
212 | + | let blockEpochBytes = toBytes(height) | |
213 | + | let blockMetaBytes = (((((toBytes(blockHeight) + blockEpochBytes) + fromBase16String(blockParentHex)) + blockGenerator.bytes) + toBytes(chainId)) + fromBase16String(elToClTransfersRootHashHex)) | |
214 | + | BinaryEntry((blockMetaK + blockHashHex), blockMetaBytes) | |
172 | 215 | } | |
173 | 216 | ||
174 | 217 | ||
175 | 218 | func lastHeightBy (miner,chainId) = match getInteger(chainLastHeightKey(chainId, miner)) { | |
176 | 219 | case h: Int => | |
177 | 220 | h | |
178 | 221 | case _ => | |
179 | 222 | let blockHash = getStringValue(((("chain" + toString(chainId)) + "LastMinedBy") + toString(miner))) | |
180 | 223 | blockMeta(blockHash)._1 | |
181 | 224 | } | |
182 | 225 | ||
183 | 226 | ||
184 | - | let $ | |
227 | + | let $t073208286 = { | |
185 | 228 | let hitSource = match lastBlock.vrf { | |
186 | 229 | case vrf: ByteVector => | |
187 | 230 | vrf | |
188 | 231 | case _ => | |
189 | 232 | lastBlock.generationSignature | |
190 | 233 | } | |
191 | 234 | func processMiner (prev,miner) = { | |
192 | - | let $ | |
193 | - | let prevDelay = $ | |
194 | - | let prevMiner = $ | |
195 | - | let prevTotalBalance = $ | |
196 | - | let prevMiners = $ | |
235 | + | let $t076187681 = prev | |
236 | + | let prevDelay = $t076187681._1 | |
237 | + | let prevMiner = $t076187681._2 | |
238 | + | let prevTotalBalance = $t076187681._3 | |
239 | + | let prevMiners = $t076187681._4 | |
197 | 240 | let minerAddress = addressFromStringValue(miner) | |
198 | 241 | let wavesGenBalance = wavesBalance(minerAddress).generating | |
199 | 242 | let minerBalance = generatingBalance(minerAddress) | |
200 | 243 | if (if ((MIN_BALANCE > wavesGenBalance)) | |
201 | 244 | then true | |
202 | 245 | else (0 >= minerBalance)) | |
203 | 246 | then prev | |
204 | 247 | else { | |
205 | 248 | let nextDelay = calculateDelay(minerAddress, minerBalance) | |
206 | 249 | if ((prevDelay > nextDelay)) | |
207 | 250 | then $Tuple4(nextDelay, miner, (prevTotalBalance + minerBalance), (prevMiners :+ miner)) | |
208 | 251 | else $Tuple4(prevDelay, prevMiner, (prevTotalBalance + minerBalance), (prevMiners :+ miner)) | |
209 | 252 | } | |
210 | 253 | } | |
211 | 254 | ||
212 | 255 | let $l = allMiners | |
213 | 256 | let $s = size($l) | |
214 | 257 | let $acc0 = $Tuple4(INT_MAX, "", 0, nil) | |
215 | 258 | func $f0_1 ($a,$i) = if (($i >= $s)) | |
216 | 259 | then $a | |
217 | 260 | else processMiner($a, $l[$i]) | |
218 | 261 | ||
219 | 262 | func $f0_2 ($a,$i) = if (($i >= $s)) | |
220 | 263 | then $a | |
221 | 264 | else throw("List size exceeds 50") | |
222 | 265 | ||
223 | 266 | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50) | |
224 | 267 | } | |
225 | 268 | ||
226 | - | let computedDelay = $ | |
269 | + | let computedDelay = $t073208286._1 | |
227 | 270 | ||
228 | - | let computedGenerator = $ | |
271 | + | let computedGenerator = $t073208286._2 | |
229 | 272 | ||
230 | - | let computedTotalBalance = $ | |
273 | + | let computedTotalBalance = $t073208286._3 | |
231 | 274 | ||
232 | - | let filteredMiners = $ | |
275 | + | let filteredMiners = $t073208286._4 | |
233 | 276 | ||
234 | 277 | func getChainLastBlockId (chainId) = chainMeta(chainId)._2 | |
235 | 278 | ||
236 | 279 | ||
237 | - | let $ | |
280 | + | let $t083528487 = blockMeta(mainChainLastBlock) | |
238 | 281 | ||
239 | - | let | |
282 | + | let mclbIgnored1 = $t083528487._1 | |
240 | 283 | ||
241 | - | let mainChainEpoch = $ | |
284 | + | let mainChainEpoch = $t083528487._2 | |
242 | 285 | ||
243 | - | let mainChainParentHash = $ | |
286 | + | let mainChainParentHash = $t083528487._3 | |
244 | 287 | ||
245 | - | let mainChainGenerator = $t053835485._4 | |
288 | + | let mainChainGenerator = $t083528487._4 | |
289 | + | ||
290 | + | let mclbIgnored2 = $t083528487._5 | |
291 | + | ||
292 | + | let mclbIgnored3 = $t083528487._6 | |
246 | 293 | ||
247 | 294 | func calculateFinalizedBlockHash (curMiner,curPrevEpoch,curLastBlockHash) = { | |
248 | 295 | let offsets_100 = split_4C("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::", "") | |
249 | 296 | let halfBalance = (computedTotalBalance / 2) | |
250 | 297 | func step (prev,next) = { | |
251 | - | let $ | |
252 | - | let thisEpoch = $ | |
253 | - | let totalBalance = $ | |
254 | - | let maybeSafeEpoch = $ | |
255 | - | let prevMiners = $ | |
298 | + | let $t088538917 = prev | |
299 | + | let thisEpoch = $t088538917._1 | |
300 | + | let totalBalance = $t088538917._2 | |
301 | + | let maybeSafeEpoch = $t088538917._3 | |
302 | + | let prevMiners = $t088538917._4 | |
256 | 303 | match maybeSafeEpoch { | |
257 | 304 | case _: Unit => | |
258 | - | let $ | |
305 | + | let $t089759141 = if ((thisEpoch == height)) | |
259 | 306 | then $Tuple3(curMiner, curPrevEpoch, curLastBlockHash) | |
260 | 307 | else value(epochMeta(thisEpoch)) | |
261 | - | let miner = $ | |
262 | - | let prevEpoch = $ | |
263 | - | let lastBlockHash = $ | |
308 | + | let miner = $t089759141._1 | |
309 | + | let prevEpoch = $t089759141._2 | |
310 | + | let lastBlockHash = $t089759141._3 | |
264 | 311 | if ((prevEpoch == 0)) | |
265 | 312 | then $Tuple4(thisEpoch, totalBalance, lastBlockHash, allMiners) | |
266 | 313 | else { | |
267 | - | let $ | |
314 | + | let $t092669468 = if (containsElement(prevMiners, miner)) | |
268 | 315 | then $Tuple2(totalBalance, prevMiners) | |
269 | 316 | else $Tuple2((totalBalance + generatingBalance(miner)), miner :: prevMiners) | |
270 | - | let newTotalBalance = $ | |
271 | - | let newMiners = $ | |
317 | + | let newTotalBalance = $t092669468._1 | |
318 | + | let newMiners = $t092669468._2 | |
272 | 319 | if ((newTotalBalance > halfBalance)) | |
273 | 320 | then $Tuple4(thisEpoch, newTotalBalance, lastBlockHash, allMiners) | |
274 | 321 | else $Tuple4(prevEpoch, newTotalBalance, unit, newMiners) | |
275 | 322 | } | |
276 | 323 | case _ => | |
277 | 324 | prev | |
278 | 325 | } | |
279 | 326 | } | |
280 | 327 | ||
281 | - | let $ | |
328 | + | let $t097019834 = { | |
282 | 329 | let $l = (offsets_100 ++ offsets_100) | |
283 | 330 | let $s = size($l) | |
284 | 331 | let $acc0 = $Tuple4(height, 0, unit, nil) | |
285 | 332 | func $f0_1 ($a,$i) = if (($i >= $s)) | |
286 | 333 | then $a | |
287 | 334 | else step($a, $l[$i]) | |
288 | 335 | ||
289 | 336 | func $f0_2 ($a,$i) = if (($i >= $s)) | |
290 | 337 | then $a | |
291 | 338 | else throw("List size exceeds 200") | |
292 | 339 | ||
293 | 340 | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100), 101), 102), 103), 104), 105), 106), 107), 108), 109), 110), 111), 112), 113), 114), 115), 116), 117), 118), 119), 120), 121), 122), 123), 124), 125), 126), 127), 128), 129), 130), 131), 132), 133), 134), 135), 136), 137), 138), 139), 140), 141), 142), 143), 144), 145), 146), 147), 148), 149), 150), 151), 152), 153), 154), 155), 156), 157), 158), 159), 160), 161), 162), 163), 164), 165), 166), 167), 168), 169), 170), 171), 172), 173), 174), 175), 176), 177), 178), 179), 180), 181), 182), 183), 184), 185), 186), 187), 188), 189), 190), 191), 192), 193), 194), 195), 196), 197), 198), 199), 200) | |
294 | 341 | } | |
295 | - | let fallbackEpoch = $ | |
296 | - | let totalBalance = $ | |
297 | - | let finalizedBlockHashOpt = $ | |
298 | - | let miners = $ | |
342 | + | let fallbackEpoch = $t097019834._1 | |
343 | + | let totalBalance = $t097019834._2 | |
344 | + | let finalizedBlockHashOpt = $t097019834._3 | |
345 | + | let miners = $t097019834._4 | |
299 | 346 | match finalizedBlockHashOpt { | |
300 | 347 | case finalizedBlockHash: String => | |
301 | 348 | finalizedBlockHash | |
302 | 349 | case _ => | |
303 | 350 | value(epochMeta(fallbackEpoch))._3 | |
304 | 351 | } | |
305 | 352 | } | |
306 | 353 | ||
307 | 354 | ||
308 | 355 | func supportingBalance (chainId) = { | |
309 | 356 | func addBalance (acc,generatorStr) = { | |
310 | - | let $ | |
311 | - | let totalBalance = $ | |
312 | - | let generators = $ | |
357 | + | let $t01010410140 = acc | |
358 | + | let totalBalance = $t01010410140._1 | |
359 | + | let generators = $t01010410140._2 | |
313 | 360 | let generator = addressFromStringValue(generatorStr) | |
314 | 361 | if (containsElement(generators, generator)) | |
315 | 362 | then acc | |
316 | 363 | else { | |
317 | 364 | let balance = generatingBalance(generator) | |
318 | 365 | $Tuple2((totalBalance + balance), (generators :+ generator)) | |
319 | 366 | } | |
320 | 367 | } | |
321 | 368 | ||
322 | 369 | let allGenerators = split_4C(getStringValue(supportersKey(chainId)), SEP) | |
323 | - | let $ | |
370 | + | let $t01046210527 = { | |
324 | 371 | let $l = allGenerators | |
325 | 372 | let $s = size($l) | |
326 | 373 | let $acc0 = $Tuple2(0, nil) | |
327 | 374 | func $f0_1 ($a,$i) = if (($i >= $s)) | |
328 | 375 | then $a | |
329 | 376 | else addBalance($a, $l[$i]) | |
330 | 377 | ||
331 | 378 | func $f0_2 ($a,$i) = if (($i >= $s)) | |
332 | 379 | then $a | |
333 | 380 | else throw("List size exceeds 100") | |
334 | 381 | ||
335 | 382 | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100) | |
336 | 383 | } | |
337 | - | let balance = $ | |
338 | - | let _g = $ | |
384 | + | let balance = $t01046210527._1 | |
385 | + | let _g = $t01046210527._2 | |
339 | 386 | balance | |
340 | 387 | } | |
341 | 388 | ||
342 | 389 | ||
343 | 390 | func isContractSetup () = isDefined(getInteger(minerRewardKey)) | |
344 | 391 | ||
345 | 392 | ||
346 | 393 | func ensureMiningEpoch (generator) = if ((toString(generator) != computedGenerator)) | |
347 | 394 | then throw(((((toBase58String(generator.bytes) + " is not allowed to mine in ") + toString(height)) + " epoch. Expected ") + computedGenerator)) | |
348 | 395 | else unit | |
349 | 396 | ||
350 | 397 | ||
351 | 398 | func isReferenceCorrect (reference,lastBlock) = if ((reference == lastBlock)) | |
352 | 399 | then unit | |
353 | 400 | else throw(((("Expected a reference to the chain last block: 0x" + lastBlock) + ". Got: 0x") + reference)) | |
354 | 401 | ||
355 | 402 | ||
356 | 403 | func chainIsInactive (chainId) = { | |
357 | 404 | let firstBlockId = getStringValue(chainFirstBlockIdKey(chainId)) | |
358 | 405 | let firstValidAltChainId = valueOrElse(getInteger(firstValidAltChainIdKey), 0) | |
359 | 406 | if ((firstValidAltChainId > chainId)) | |
360 | 407 | then true | |
361 | 408 | else (blockMeta(getStringValue(finalizedBlockKey))._1 > blockMeta(firstBlockId)._1) | |
362 | 409 | } | |
363 | 410 | ||
364 | 411 | ||
365 | 412 | func minerChainId (miner) = valueOrElse(getInteger(minerChainIdKey(miner)), getInteger(("chainIdOf" + toString(miner)))) | |
366 | 413 | ||
367 | 414 | ||
368 | 415 | func ensureExpectedOrInactiveChain (generator,expectedChainId,checkHeightBlock) = { | |
369 | 416 | let heightIsCorrect = match checkHeightBlock { | |
370 | 417 | case blockHash: String => | |
371 | 418 | let lastMinedBlockHeight = lastHeightBy(generator, mainChainId) | |
372 | 419 | ((blockMeta(blockHash)._1 + 1) > lastMinedBlockHeight) | |
373 | 420 | case _ => | |
374 | 421 | true | |
375 | 422 | } | |
376 | 423 | match minerChainId(generator) { | |
377 | 424 | case currentId: Int => | |
378 | 425 | if (if ((currentId == expectedChainId)) | |
379 | 426 | then true | |
380 | 427 | else if (chainIsInactive(currentId)) | |
381 | 428 | then heightIsCorrect | |
382 | 429 | else false) | |
383 | 430 | then unit | |
384 | 431 | else throw(("miner is mining other chain " + toString(currentId))) | |
385 | 432 | case _ => | |
386 | 433 | unit | |
387 | 434 | } | |
388 | 435 | } | |
389 | 436 | ||
390 | 437 | ||
391 | 438 | func ensureCorrectEpoch (epoch) = if ((epoch == height)) | |
392 | 439 | then unit | |
393 | 440 | else throw(((("Expected block from epoch " + toString(height)) + ". Got ") + toString(epoch))) | |
394 | 441 | ||
395 | 442 | ||
396 | 443 | func addSupporter (chainId,generator) = { | |
397 | 444 | let supportersStr = getStringValue(supportersKey(chainId)) | |
398 | 445 | let supporters = split_4C(supportersStr, SEP) | |
399 | 446 | if (containsElement(supporters, toString(generator))) | |
400 | 447 | then nil | |
401 | 448 | else [StringEntry(supportersKey(chainId), ((supportersStr + SEP) + toString(generator)))] | |
402 | 449 | } | |
403 | 450 | ||
404 | 451 | ||
452 | + | func setOrFail (flags,index) = if ((0 > index)) | |
453 | + | then throw(("Can't withdraw at negative index: " + toString(index))) | |
454 | + | else { | |
455 | + | let flagsSize = size(flags) | |
456 | + | if ((index >= flagsSize)) | |
457 | + | then { | |
458 | + | let addZeroes = (index - flagsSize) | |
459 | + | if ((addZeroes > size(zeroesStr))) | |
460 | + | then throw((("Can't add " + toString(addZeroes)) + " empty flags. Contact with developers")) | |
461 | + | else ((flags + take(zeroesStr, addZeroes)) + "1") | |
462 | + | } | |
463 | + | else { | |
464 | + | let tail = drop(flags, index) | |
465 | + | let atIndex = take(tail, 1) | |
466 | + | if ((atIndex == "0")) | |
467 | + | then ((take(flags, index) + "1") + drop(tail, 1)) | |
468 | + | else throw((("Transfer #" + toString(index)) + " has been already taken")) | |
469 | + | } | |
470 | + | } | |
471 | + | ||
472 | + | ||
405 | 473 | func validateBlockHash (hexStr) = { | |
406 | 474 | let decodedBytes = fromBase16String(hexStr) | |
407 | 475 | if ((size(decodedBytes) != 32)) | |
408 | 476 | then throw("invalid block id length") | |
409 | 477 | else hexStr | |
410 | 478 | } | |
411 | 479 | ||
412 | 480 | ||
413 | 481 | func getUpdateFinalizedBlockAction (caller,newBlockHashHex,prevEpoch) = { | |
414 | 482 | let curFinalizedBlockHeight = blockMeta(getStringValue(finalizedBlockKey))._1 | |
415 | 483 | let newFinalizedBlockHash = calculateFinalizedBlockHash(caller, prevEpoch, newBlockHashHex) | |
416 | - | if ((newFinalizedBlockHash == newBlockHashHex)) | |
484 | + | if (if ((newFinalizedBlockHash == newBlockHashHex)) | |
485 | + | then true | |
486 | + | else (blockMeta(newFinalizedBlockHash)._1 > curFinalizedBlockHeight)) | |
417 | 487 | then [StringEntry(finalizedBlockKey, newFinalizedBlockHash)] | |
418 | - | else if ((blockMeta(newFinalizedBlockHash)._1 > curFinalizedBlockHeight)) | |
419 | - | then [StringEntry(finalizedBlockKey, newFinalizedBlockHash)] | |
420 | - | else nil | |
488 | + | else nil | |
421 | 489 | } | |
422 | 490 | ||
423 | 491 | ||
424 | 492 | @Callable(i) | |
425 | - | func appendBlock (blockHashHex,referenceHex) = if ((thisEpochMiner != i.originCaller)) | |
426 | - | then match thisEpochMiner { | |
427 | - | case epochMiner: Address => | |
428 | - | throw(("not allowed to forge blocks in this epoch, expected from " + toString(epochMiner))) | |
429 | - | case _ => | |
430 | - | throw("not allowed to forge blocks in this epoch, epoch miner is absent") | |
493 | + | func appendBlock (blockHashHex,referenceHex) = { | |
494 | + | let checkVersion = requireElToClTransfersDisabled() | |
495 | + | if ((checkVersion == checkVersion)) | |
496 | + | then if ((thisEpochMiner != i.originCaller)) | |
497 | + | then match thisEpochMiner { | |
498 | + | case epochMiner: Address => | |
499 | + | throw(("not allowed to forge blocks in this epoch, expected from " + toString(epochMiner))) | |
500 | + | case _ => | |
501 | + | throw("not allowed to forge blocks in this epoch, epoch miner is absent") | |
502 | + | } | |
503 | + | else { | |
504 | + | let chainId = valueOrElse(minerChainId(i.originCaller), mainChainId) | |
505 | + | let $t01464414695 = chainMeta(chainId) | |
506 | + | let chainHeight = $t01464414695._1 | |
507 | + | let lastBlockId = $t01464414695._2 | |
508 | + | let checkReference = isReferenceCorrect(referenceHex, lastBlockId) | |
509 | + | if ((checkReference == checkReference)) | |
510 | + | then { | |
511 | + | let newChainHeight = (chainHeight + 1) | |
512 | + | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(lastBlockId)) + i.originCaller.bytes) | |
513 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
514 | + | if ((checkBlockHash == checkBlockHash)) | |
515 | + | then [BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), StringEntry(epochMetaKey(height), ((((toString(value(thisEpochMiner)) + SEP) + toString(thisEpochRef)) + SEP) + blockHashHex))] | |
516 | + | else throw("Strict value is not equal to itself.") | |
517 | + | } | |
518 | + | else throw("Strict value is not equal to itself.") | |
519 | + | } | |
520 | + | else throw("Strict value is not equal to itself.") | |
431 | 521 | } | |
432 | - | else { | |
433 | - | let chainId = valueOrElse(minerChainId(i.originCaller), mainChainId) | |
434 | - | let $t01083310884 = chainMeta(chainId) | |
435 | - | let chainHeight = $t01083310884._1 | |
436 | - | let lastBlockId = $t01083310884._2 | |
437 | - | let checkReference = isReferenceCorrect(referenceHex, lastBlockId) | |
438 | - | if ((checkReference == checkReference)) | |
439 | - | then { | |
440 | - | let newChainHeight = (chainHeight + 1) | |
441 | - | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(lastBlockId)) + i.originCaller.bytes) | |
442 | - | let blockHash = validateBlockHash(blockHashHex) | |
443 | - | [BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), StringEntry(epochMetaKey(height), ((((toString(value(thisEpochMiner)) + SEP) + toString(thisEpochRef)) + SEP) + blockHashHex))] | |
522 | + | ||
523 | + | ||
524 | + | ||
525 | + | @Callable(i) | |
526 | + | func appendBlock_v2 (blockHashHex,referenceHex,elToClTransfersRootHashHex) = { | |
527 | + | let checkVersion = requireElToClTransfersEnabled() | |
528 | + | if ((checkVersion == checkVersion)) | |
529 | + | then if ((thisEpochMiner != i.originCaller)) | |
530 | + | then match thisEpochMiner { | |
531 | + | case epochMiner: Address => | |
532 | + | throw(("not allowed to forge blocks in this epoch, expected from " + toString(epochMiner))) | |
533 | + | case _ => | |
534 | + | throw("not allowed to forge blocks in this epoch, epoch miner is absent") | |
535 | + | } | |
536 | + | else { | |
537 | + | let chainId = valueOrElse(minerChainId(i.originCaller), mainChainId) | |
538 | + | let $t01596916020 = chainMeta(chainId) | |
539 | + | let chainHeight = $t01596916020._1 | |
540 | + | let lastBlockId = $t01596916020._2 | |
541 | + | let checkReference = isReferenceCorrect(referenceHex, lastBlockId) | |
542 | + | if ((checkReference == checkReference)) | |
543 | + | then { | |
544 | + | let newChainHeight = (chainHeight + 1) | |
545 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
546 | + | if ((checkBlockHash == checkBlockHash)) | |
547 | + | then [mkBlockMetaEntry(blockHashHex, newChainHeight, lastBlockId, i.originCaller, chainId, elToClTransfersRootHashHex), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), StringEntry(epochMetaKey(height), ((((toString(value(thisEpochMiner)) + SEP) + toString(thisEpochRef)) + SEP) + blockHashHex))] | |
548 | + | else throw("Strict value is not equal to itself.") | |
549 | + | } | |
550 | + | else throw("Strict value is not equal to itself.") | |
444 | 551 | } | |
445 | - | ||
446 | - | ||
552 | + | else throw("Strict value is not equal to itself.") | |
553 | + | } | |
447 | 554 | ||
448 | 555 | ||
449 | 556 | ||
450 | 557 | @Callable(i) | |
451 | 558 | func extendMainChain (blockHashHex,referenceHex,epoch) = { | |
452 | - | let | |
453 | - | if (( | |
559 | + | let checkVersion = requireElToClTransfersDisabled() | |
560 | + | if ((checkVersion == checkVersion)) | |
454 | 561 | then { | |
455 | - | let | |
456 | - | if (( | |
562 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
563 | + | if ((checkBlockHash == checkBlockHash)) | |
457 | 564 | then { | |
458 | - | let | |
459 | - | if (( | |
565 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
566 | + | if ((checkEpoch == checkEpoch)) | |
460 | 567 | then { | |
461 | - | let | |
462 | - | if (( | |
568 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
569 | + | if ((checkGenerator == checkGenerator)) | |
463 | 570 | then { | |
464 | - | let thisEpochMeta = match epochMeta(height) { | |
465 | - | case _: Unit => | |
466 | - | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(mainChainEpoch)) + SEP) + blockHashHex)) | |
467 | - | case other => | |
468 | - | throw("Epoch already started") | |
571 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, unit) | |
572 | + | if ((checkChain == checkChain)) | |
573 | + | then { | |
574 | + | let checkReference = isReferenceCorrect(referenceHex, mainChainLastBlock) | |
575 | + | if ((checkReference == checkReference)) | |
576 | + | then { | |
577 | + | let thisEpochMeta = match epochMeta(height) { | |
578 | + | case _: Unit => | |
579 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(mainChainEpoch)) + SEP) + blockHashHex)) | |
580 | + | case other => | |
581 | + | throw("Epoch already started") | |
582 | + | } | |
583 | + | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, mainChainEpoch) | |
584 | + | let newChainHeight = (mainChainHeight + 1) | |
585 | + | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(mainChainLastBlock)) + i.originCaller.bytes) | |
586 | + | ([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(mainChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), mainChainId), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), thisEpochMeta] ++ updateFinalizedBlock) | |
587 | + | } | |
588 | + | else throw("Strict value is not equal to itself.") | |
589 | + | } | |
590 | + | else throw("Strict value is not equal to itself.") | |
469 | 591 | } | |
470 | - | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, mainChainEpoch) | |
471 | - | let newChainHeight = (mainChainHeight + 1) | |
472 | - | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(mainChainLastBlock)) + i.originCaller.bytes) | |
473 | - | ([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(mainChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), mainChainId), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), thisEpochMeta] ++ updateFinalizedBlock) | |
592 | + | else throw("Strict value is not equal to itself.") | |
593 | + | } | |
594 | + | else throw("Strict value is not equal to itself.") | |
595 | + | } | |
596 | + | else throw("Strict value is not equal to itself.") | |
597 | + | } | |
598 | + | else throw("Strict value is not equal to itself.") | |
599 | + | } | |
600 | + | ||
601 | + | ||
602 | + | ||
603 | + | @Callable(i) | |
604 | + | func extendMainChain_v2 (blockHashHex,referenceHex,epoch,elToClTransfersRootHashHex) = { | |
605 | + | let checkVersion = requireElToClTransfersEnabled() | |
606 | + | if ((checkVersion == checkVersion)) | |
607 | + | then { | |
608 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
609 | + | if ((checkBlockHash == checkBlockHash)) | |
610 | + | then { | |
611 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
612 | + | if ((checkEpoch == checkEpoch)) | |
613 | + | then { | |
614 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
615 | + | if ((checkGenerator == checkGenerator)) | |
616 | + | then { | |
617 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, unit) | |
618 | + | if ((checkChain == checkChain)) | |
619 | + | then { | |
620 | + | let checkReference = isReferenceCorrect(referenceHex, mainChainLastBlock) | |
621 | + | if ((checkReference == checkReference)) | |
622 | + | then { | |
623 | + | let thisEpochMeta = match epochMeta(height) { | |
624 | + | case _: Unit => | |
625 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(mainChainEpoch)) + SEP) + blockHashHex)) | |
626 | + | case other => | |
627 | + | throw("Epoch already started") | |
628 | + | } | |
629 | + | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, mainChainEpoch) | |
630 | + | let newChainHeight = (mainChainHeight + 1) | |
631 | + | ([mkBlockMetaEntry(blockHashHex, newChainHeight, mainChainLastBlock, i.originCaller, mainChainId, elToClTransfersRootHashHex), StringEntry(chainMetaKey(mainChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), mainChainId), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), thisEpochMeta] ++ updateFinalizedBlock) | |
632 | + | } | |
633 | + | else throw("Strict value is not equal to itself.") | |
634 | + | } | |
635 | + | else throw("Strict value is not equal to itself.") | |
474 | 636 | } | |
475 | 637 | else throw("Strict value is not equal to itself.") | |
476 | 638 | } | |
477 | 639 | else throw("Strict value is not equal to itself.") | |
478 | 640 | } | |
479 | 641 | else throw("Strict value is not equal to itself.") | |
480 | 642 | } | |
481 | 643 | else throw("Strict value is not equal to itself.") | |
482 | 644 | } | |
483 | 645 | ||
484 | 646 | ||
485 | 647 | ||
486 | 648 | @Callable(i) | |
487 | 649 | func startAltChain (blockHashHex,referenceHex,epoch) = { | |
488 | - | let | |
489 | - | if (( | |
650 | + | let checkVersion = requireElToClTransfersDisabled() | |
651 | + | if ((checkVersion == checkVersion)) | |
490 | 652 | then { | |
491 | - | let | |
492 | - | if (( | |
653 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
654 | + | if ((checkBlockHash == checkBlockHash)) | |
493 | 655 | then { | |
494 | - | let $t01309313171 = blockMeta(referenceHex) | |
495 | - | let refChainHeight = $t01309313171._1 | |
496 | - | let refEpoch = $t01309313171._2 | |
497 | - | let refRef = $t01309313171._3 | |
498 | - | let refGenerator = $t01309313171._4 | |
499 | - | let finalizedEpoch = blockMeta(getStringValue(finalizedBlockKey))._2 | |
500 | - | let epochRef = if ((refEpoch >= finalizedEpoch)) | |
501 | - | then refEpoch | |
502 | - | else throw((((("can not start alt chain from epoch " + toString(refEpoch)) + ", epoch ") + toString(finalizedEpoch)) + " is finalized")) | |
503 | - | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, referenceHex) | |
504 | - | if ((checkChain == checkChain)) | |
656 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
657 | + | if ((checkEpoch == checkEpoch)) | |
505 | 658 | then { | |
506 | - | let newChainId = (valueOrElse(getInteger(lastChainIdKey), 0) + 1) | |
507 | - | let referenceHeight = blockMeta(referenceHex)._1 | |
508 | - | let newChainHeight = (referenceHeight + 1) | |
509 | - | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(referenceHex)) + i.originCaller.bytes) | |
510 | - | let thisEpochMeta = match epochMeta(height) { | |
511 | - | case _: Unit => | |
512 | - | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(epochRef)) + SEP) + blockHashHex)) | |
513 | - | case other => | |
514 | - | throw("Epoch already started") | |
659 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
660 | + | if ((checkGenerator == checkGenerator)) | |
661 | + | then { | |
662 | + | let $t01969819802 = blockMeta(referenceHex) | |
663 | + | let refChainHeight = $t01969819802._1 | |
664 | + | let refEpoch = $t01969819802._2 | |
665 | + | let refRef = $t01969819802._3 | |
666 | + | let refGenerator = $t01969819802._4 | |
667 | + | let refIgnored1 = $t01969819802._5 | |
668 | + | let refIgnored2 = $t01969819802._6 | |
669 | + | let finalizedEpoch = blockMeta(getStringValue(finalizedBlockKey))._2 | |
670 | + | let epochRef = if ((refEpoch >= finalizedEpoch)) | |
671 | + | then refEpoch | |
672 | + | else throw((((("can not start alt chain from epoch " + toString(refEpoch)) + ", epoch ") + toString(finalizedEpoch)) + " is finalized")) | |
673 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, referenceHex) | |
674 | + | if ((checkChain == checkChain)) | |
675 | + | then { | |
676 | + | let newChainId = (valueOrElse(getInteger(lastChainIdKey), 0) + 1) | |
677 | + | let newChainHeight = (blockMeta(referenceHex)._1 + 1) | |
678 | + | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(referenceHex)) + i.originCaller.bytes) | |
679 | + | let thisEpochMeta = match epochMeta(height) { | |
680 | + | case _: Unit => | |
681 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(epochRef)) + SEP) + blockHashHex)) | |
682 | + | case other => | |
683 | + | throw("Epoch already started") | |
684 | + | } | |
685 | + | [thisEpochMeta, BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainFirstBlockIdKey(newChainId), blockHashHex), StringEntry(chainMetaKey(newChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), newChainId), IntegerEntry(chainLastHeightKey(newChainId, i.originCaller), newChainHeight), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), StringEntry(supportersKey(newChainId), toString(i.originCaller)), IntegerEntry(lastChainIdKey, newChainId)] | |
686 | + | } | |
687 | + | else throw("Strict value is not equal to itself.") | |
688 | + | } | |
689 | + | else throw("Strict value is not equal to itself.") | |
515 | 690 | } | |
516 | - | [thisEpochMeta, BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainFirstBlockIdKey(newChainId), blockHashHex), StringEntry(chainMetaKey(newChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), newChainId), IntegerEntry(chainLastHeightKey(newChainId, i.originCaller), newChainHeight), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), referenceHeight), StringEntry(supportersKey(newChainId), toString(i.originCaller)), IntegerEntry(lastChainIdKey, newChainId)] | |
691 | + | else throw("Strict value is not equal to itself.") | |
692 | + | } | |
693 | + | else throw("Strict value is not equal to itself.") | |
694 | + | } | |
695 | + | else throw("Strict value is not equal to itself.") | |
696 | + | } | |
697 | + | ||
698 | + | ||
699 | + | ||
700 | + | @Callable(i) | |
701 | + | func startAltChain_v2 (blockHashHex,referenceHex,epoch,elToClTransfersRootHashHex) = { | |
702 | + | let checkVersion = requireElToClTransfersEnabled() | |
703 | + | if ((checkVersion == checkVersion)) | |
704 | + | then { | |
705 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
706 | + | if ((checkBlockHash == checkBlockHash)) | |
707 | + | then { | |
708 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
709 | + | if ((checkEpoch == checkEpoch)) | |
710 | + | then { | |
711 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
712 | + | if ((checkGenerator == checkGenerator)) | |
713 | + | then { | |
714 | + | let $t02161221716 = blockMeta(referenceHex) | |
715 | + | let refChainHeight = $t02161221716._1 | |
716 | + | let refEpoch = $t02161221716._2 | |
717 | + | let refRef = $t02161221716._3 | |
718 | + | let refGenerator = $t02161221716._4 | |
719 | + | let refIgnored1 = $t02161221716._5 | |
720 | + | let refIgnored2 = $t02161221716._6 | |
721 | + | let finalizedEpoch = blockMeta(getStringValue(finalizedBlockKey))._2 | |
722 | + | let epochRef = if ((refEpoch >= finalizedEpoch)) | |
723 | + | then refEpoch | |
724 | + | else throw((((("can not start alt chain from epoch " + toString(refEpoch)) + ", epoch ") + toString(finalizedEpoch)) + " is finalized")) | |
725 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, referenceHex) | |
726 | + | if ((checkChain == checkChain)) | |
727 | + | then { | |
728 | + | let newChainId = (valueOrElse(getInteger(lastChainIdKey), 0) + 1) | |
729 | + | let newChainHeight = (blockMeta(referenceHex)._1 + 1) | |
730 | + | let thisEpochMeta = match epochMeta(height) { | |
731 | + | case _: Unit => | |
732 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(epochRef)) + SEP) + blockHashHex)) | |
733 | + | case other => | |
734 | + | throw("Epoch already started") | |
735 | + | } | |
736 | + | [thisEpochMeta, mkBlockMetaEntry(blockHashHex, newChainHeight, referenceHex, i.originCaller, newChainId, elToClTransfersRootHashHex), StringEntry(chainFirstBlockIdKey(newChainId), blockHashHex), StringEntry(chainMetaKey(newChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), newChainId), IntegerEntry(chainLastHeightKey(newChainId, i.originCaller), newChainHeight), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), StringEntry(supportersKey(newChainId), toString(i.originCaller)), IntegerEntry(lastChainIdKey, newChainId)] | |
737 | + | } | |
738 | + | else throw("Strict value is not equal to itself.") | |
739 | + | } | |
740 | + | else throw("Strict value is not equal to itself.") | |
517 | 741 | } | |
518 | 742 | else throw("Strict value is not equal to itself.") | |
519 | 743 | } | |
520 | 744 | else throw("Strict value is not equal to itself.") | |
521 | 745 | } | |
522 | 746 | else throw("Strict value is not equal to itself.") | |
523 | 747 | } | |
524 | 748 | ||
525 | 749 | ||
526 | 750 | ||
527 | 751 | @Callable(i) | |
528 | 752 | func extendAltChain (chainId,blockHashHex,referenceHex,epoch) = { | |
529 | - | let | |
530 | - | if (( | |
753 | + | let checkVersion = requireElToClTransfersDisabled() | |
754 | + | if ((checkVersion == checkVersion)) | |
531 | 755 | then { | |
532 | - | let | |
533 | - | if (( | |
756 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
757 | + | if ((checkBlockHash == checkBlockHash)) | |
534 | 758 | then { | |
535 | - | let | |
536 | - | if (( | |
759 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
760 | + | if ((checkEpoch == checkEpoch)) | |
537 | 761 | then { | |
538 | - | let $t01534015394 = chainMeta(chainId) | |
539 | - | let chainHeight = $t01534015394._1 | |
540 | - | let chainLastBlock = $t01534015394._2 | |
541 | - | let checkReference = isReferenceCorrect(referenceHex, chainLastBlock) | |
542 | - | if ((checkReference == checkReference)) | |
762 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
763 | + | if ((checkGenerator == checkGenerator)) | |
543 | 764 | then { | |
544 | - | let | |
545 | - | let | |
546 | - | | |
765 | + | let chainFirstBlockMeta = blockMeta(getStringValue(chainFirstBlockIdKey(chainId))) | |
766 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, chainId, toBase16String(chainFirstBlockMeta._3)) | |
767 | + | if ((checkChain == checkChain)) | |
547 | 768 | then { | |
548 | - | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, prevEpoch) | |
549 | - | ([IntegerEntry(mainChainIdKey, chainId), IntegerEntry(firstValidAltChainIdKey, (valueOrElse(getInteger(lastChainIdKey), 0) + 1))] ++ updateFinalizedBlock) | |
769 | + | let $t02395524009 = chainMeta(chainId) | |
770 | + | let chainHeight = $t02395524009._1 | |
771 | + | let chainLastBlock = $t02395524009._2 | |
772 | + | let checkReference = isReferenceCorrect(referenceHex, chainLastBlock) | |
773 | + | if ((checkReference == checkReference)) | |
774 | + | then { | |
775 | + | let newChainHeight = (chainHeight + 1) | |
776 | + | let prevEpoch = blockMeta(referenceHex)._2 | |
777 | + | let updateMainChainData = if ((supportingBalance(chainId) > (computedTotalBalance / 2))) | |
778 | + | then { | |
779 | + | let lastChainId = valueOrElse(getInteger(lastChainIdKey), 0) | |
780 | + | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, prevEpoch) | |
781 | + | ([IntegerEntry(chainForkedHeightKey(mainChainId), chainFirstBlockMeta._1), IntegerEntry(mainChainIdKey, chainId), IntegerEntry(firstValidAltChainIdKey, (lastChainId + 1))] ++ updateFinalizedBlock) | |
782 | + | } | |
783 | + | else nil | |
784 | + | let thisEpochMeta = match epochMeta(height) { | |
785 | + | case _: Unit => | |
786 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(prevEpoch)) + SEP) + blockHashHex)) | |
787 | + | case other => | |
788 | + | throw("Epoch already started") | |
789 | + | } | |
790 | + | let updateMainChainLastMinedBlock = if (if ((updateMainChainData == nil)) | |
791 | + | then (valueOrElse(minerChainId(i.originCaller), 0) != chainId) | |
792 | + | else false) | |
793 | + | then [IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), chainFirstBlockMeta._1)] | |
794 | + | else nil | |
795 | + | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(referenceHex)) + i.originCaller.bytes) | |
796 | + | ((([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), thisEpochMeta, IntegerEntry(minerChainIdKey(i.originCaller), chainId), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight)] ++ updateMainChainData) ++ addSupporter(chainId, i.originCaller)) ++ updateMainChainLastMinedBlock) | |
797 | + | } | |
798 | + | else throw("Strict value is not equal to itself.") | |
550 | 799 | } | |
551 | - | else nil | |
552 | - | let thisEpochMeta = match epochMeta(height) { | |
553 | - | case _: Unit => | |
554 | - | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(prevEpoch)) + SEP) + blockHashHex)) | |
555 | - | case other => | |
556 | - | throw("Epoch already started") | |
800 | + | else throw("Strict value is not equal to itself.") | |
557 | 801 | } | |
558 | - | let updateMainChainLastMinedBlock = if (if ((updateMainChainData == nil)) | |
559 | - | then (valueOrElse(minerChainId(i.originCaller), 0) != chainId) | |
560 | - | else false) | |
561 | - | then [IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), blockMeta(getStringValue(chainFirstBlockIdKey(chainId)))._1)] | |
562 | - | else nil | |
563 | - | let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(referenceHex)) + i.originCaller.bytes) | |
564 | - | ((([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), thisEpochMeta, IntegerEntry(minerChainIdKey(i.originCaller), chainId), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight)] ++ updateMainChainData) ++ addSupporter(chainId, i.originCaller)) ++ updateMainChainLastMinedBlock) | |
802 | + | else throw("Strict value is not equal to itself.") | |
803 | + | } | |
804 | + | else throw("Strict value is not equal to itself.") | |
805 | + | } | |
806 | + | else throw("Strict value is not equal to itself.") | |
807 | + | } | |
808 | + | else throw("Strict value is not equal to itself.") | |
809 | + | } | |
810 | + | ||
811 | + | ||
812 | + | ||
813 | + | @Callable(i) | |
814 | + | func extendAltChain_v2 (chainId,blockHashHex,referenceHex,epoch,elToClTransfersRootHashHex) = { | |
815 | + | let checkVersion = requireElToClTransfersEnabled() | |
816 | + | if ((checkVersion == checkVersion)) | |
817 | + | then { | |
818 | + | let checkBlockHash = validateBlockHash(blockHashHex) | |
819 | + | if ((checkBlockHash == checkBlockHash)) | |
820 | + | then { | |
821 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
822 | + | if ((checkEpoch == checkEpoch)) | |
823 | + | then { | |
824 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
825 | + | if ((checkGenerator == checkGenerator)) | |
826 | + | then { | |
827 | + | let chainFirstBlockMeta = blockMeta(getStringValue(chainFirstBlockIdKey(chainId))) | |
828 | + | let checkChain = ensureExpectedOrInactiveChain(i.originCaller, chainId, toBase16String(chainFirstBlockMeta._3)) | |
829 | + | if ((checkChain == checkChain)) | |
830 | + | then { | |
831 | + | let $t02661226666 = chainMeta(chainId) | |
832 | + | let chainHeight = $t02661226666._1 | |
833 | + | let chainLastBlock = $t02661226666._2 | |
834 | + | let checkReference = isReferenceCorrect(referenceHex, chainLastBlock) | |
835 | + | if ((checkReference == checkReference)) | |
836 | + | then { | |
837 | + | let newChainHeight = (chainHeight + 1) | |
838 | + | let prevEpoch = blockMeta(referenceHex)._2 | |
839 | + | let updateMainChainData = if ((supportingBalance(chainId) > (computedTotalBalance / 2))) | |
840 | + | then { | |
841 | + | let lastChainId = valueOrElse(getInteger(lastChainIdKey), 0) | |
842 | + | let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, prevEpoch) | |
843 | + | ([IntegerEntry(chainForkedHeightKey(mainChainId), chainFirstBlockMeta._1), IntegerEntry(mainChainIdKey, chainId), IntegerEntry(firstValidAltChainIdKey, (lastChainId + 1))] ++ updateFinalizedBlock) | |
844 | + | } | |
845 | + | else nil | |
846 | + | let thisEpochMeta = match epochMeta(height) { | |
847 | + | case _: Unit => | |
848 | + | StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(prevEpoch)) + SEP) + blockHashHex)) | |
849 | + | case other => | |
850 | + | throw("Epoch already started") | |
851 | + | } | |
852 | + | let updateMainChainLastMinedBlock = if (if ((updateMainChainData == nil)) | |
853 | + | then (valueOrElse(minerChainId(i.originCaller), 0) != chainId) | |
854 | + | else false) | |
855 | + | then [IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), chainFirstBlockMeta._1)] | |
856 | + | else nil | |
857 | + | ((([mkBlockMetaEntry(blockHashHex, newChainHeight, referenceHex, i.originCaller, chainId, elToClTransfersRootHashHex), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), thisEpochMeta, IntegerEntry(minerChainIdKey(i.originCaller), chainId), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight)] ++ updateMainChainData) ++ addSupporter(chainId, i.originCaller)) ++ updateMainChainLastMinedBlock) | |
858 | + | } | |
859 | + | else throw("Strict value is not equal to itself.") | |
860 | + | } | |
861 | + | else throw("Strict value is not equal to itself.") | |
565 | 862 | } | |
566 | 863 | else throw("Strict value is not equal to itself.") | |
567 | 864 | } | |
568 | 865 | else throw("Strict value is not equal to itself.") | |
569 | 866 | } | |
570 | 867 | else throw("Strict value is not equal to itself.") | |
571 | 868 | } | |
572 | 869 | else throw("Strict value is not equal to itself.") | |
573 | 870 | } | |
574 | 871 | ||
575 | 872 | ||
576 | 873 | ||
577 | 874 | @Callable(i) | |
578 | 875 | func join (rewardAddress) = { | |
579 | 876 | func checkRewardAddress (address) = match getBinary(minerPkKey(address)) { | |
580 | 877 | case pk: ByteVector => | |
581 | 878 | if ((pk == i.originCallerPublicKey)) | |
582 | 879 | then unit | |
583 | 880 | else throw(((("L2 miner address " + address) + " is already linked with ") + toBase58String(pk))) | |
584 | 881 | case _ => | |
585 | 882 | unit | |
586 | 883 | } | |
587 | 884 | ||
588 | 885 | if (!(isContractSetup())) | |
589 | 886 | then throw("The contract has not yet set up") | |
590 | 887 | else if ((MIN_BALANCE > wavesBalance(i.originCaller).generating)) | |
591 | 888 | then throw(((("Insufficient generating balance: " + toString(wavesBalance(i.originCaller).generating)) + ". Required: ") + toString(MIN_BALANCE))) | |
592 | 889 | else if ((size(rewardAddress) != 20)) | |
593 | 890 | then throw("rewardAddress should be an L2 address") | |
594 | 891 | else if ((size(allMiners) >= 50)) | |
595 | 892 | then throw("too many miners") | |
596 | 893 | else { | |
597 | 894 | func checkExistence (exists,miner) = if (exists) | |
598 | 895 | then true | |
599 | 896 | else (miner == toString(i.originCaller)) | |
600 | 897 | ||
601 | 898 | let alreadyExists = { | |
602 | 899 | let $l = allMiners | |
603 | 900 | let $s = size($l) | |
604 | 901 | let $acc0 = false | |
605 | 902 | func $f0_1 ($a,$i) = if (($i >= $s)) | |
606 | 903 | then $a | |
607 | 904 | else checkExistence($a, $l[$i]) | |
608 | 905 | ||
609 | 906 | func $f0_2 ($a,$i) = if (($i >= $s)) | |
610 | 907 | then $a | |
611 | 908 | else throw("List size exceeds 50") | |
612 | 909 | ||
613 | 910 | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50) | |
614 | 911 | } | |
615 | 912 | if (alreadyExists) | |
616 | 913 | then nil | |
617 | 914 | else { | |
618 | 915 | let newMiner = toString(i.originCaller) | |
619 | 916 | let rewardAddressHex = toBase16String(rewardAddress) | |
620 | 917 | let check = checkRewardAddress(rewardAddressHex) | |
621 | 918 | if ((check == check)) | |
622 | 919 | then { | |
623 | 920 | let newMiners = if ((size(allMiners) == 0)) | |
624 | 921 | then newMiner | |
625 | 922 | else ((allMinersStr + SEP) + newMiner) | |
626 | 923 | let deleteOldRewardAddressPk = match getString(minerRewardAddressKey(newMiner)) { | |
627 | 924 | case oldAddress: String => | |
628 | 925 | if ((oldAddress == toBase16String(rewardAddress))) | |
629 | 926 | then nil | |
630 | 927 | else [DeleteEntry(minerPkKey(oldAddress))] | |
631 | 928 | case _ => | |
632 | 929 | nil | |
633 | 930 | } | |
634 | 931 | ([StringEntry(allMinersKey, newMiners), StringEntry(minerRewardAddressKey(newMiner), ("0x" + rewardAddressHex)), BinaryEntry(minerPkKey(rewardAddressHex), i.originCallerPublicKey)] ++ deleteOldRewardAddressPk) | |
635 | 932 | } | |
636 | 933 | else throw("Strict value is not equal to itself.") | |
637 | 934 | } | |
638 | 935 | } | |
639 | 936 | } | |
640 | 937 | ||
641 | 938 | ||
642 | 939 | ||
643 | 940 | @Callable(i) | |
644 | 941 | func leave () = { | |
645 | 942 | let leavingMiner = toString(i.originCaller) | |
646 | 943 | func skipLeavingMiner (acc,miner) = if ((miner == leavingMiner)) | |
647 | 944 | then acc | |
648 | 945 | else (acc :+ miner) | |
649 | 946 | ||
650 | 947 | let remainingMiners = { | |
651 | 948 | let $l = allMiners | |
652 | 949 | let $s = size($l) | |
653 | 950 | let $acc0 = nil | |
654 | 951 | func $f0_1 ($a,$i) = if (($i >= $s)) | |
655 | 952 | then $a | |
656 | 953 | else skipLeavingMiner($a, $l[$i]) | |
657 | 954 | ||
658 | 955 | func $f0_2 ($a,$i) = if (($i >= $s)) | |
659 | 956 | then $a | |
660 | 957 | else throw("List size exceeds 50") | |
661 | 958 | ||
662 | 959 | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50) | |
663 | 960 | } | |
664 | 961 | let rewardAddrKey = minerRewardAddressKey(leavingMiner) | |
665 | 962 | let prevRewardAddress = valueOrErrorMessage(getString(this, rewardAddrKey), "miner has never joined") | |
666 | 963 | if ((thisEpochMiner == i.originCaller)) | |
667 | 964 | then throw("designated miner can't leave") | |
668 | 965 | else [StringEntry(allMinersKey, makeString_2C(remainingMiners, SEP)), DeleteEntry(rewardAddrKey), DeleteEntry(minerPkKey(prevRewardAddress))] | |
669 | 966 | } | |
670 | 967 | ||
671 | 968 | ||
672 | 969 | ||
673 | 970 | @Callable(i) | |
674 | - | func setup (genesisBlockHashHex,minerReward,stakingContractAddressB58) = if (isContractSetup()) | |
971 | + | func withdraw (blockHashHex,merkleProof,transferIndexInBlock,amount) = { | |
972 | + | let checkActivation = requireElToClTransfersEnabled() | |
973 | + | if ((checkActivation == checkActivation)) | |
974 | + | then { | |
975 | + | let withdrawBlockMeta = blockMeta(blockHashHex) | |
976 | + | let withdrawBlockHeight = withdrawBlockMeta._1 | |
977 | + | let finalizedBlockHeight = blockMeta(getStringValue(finalizedBlockKey))._1 | |
978 | + | let mainChainLastBlockHeight = blockMeta(mainChainLastBlock)._1 | |
979 | + | if ((withdrawBlockHeight > finalizedBlockHeight)) | |
980 | + | then throw(((("EL block #" + toString(withdrawBlockHeight)) + " is not finalized. The current finalized is #") + toString(finalizedBlockHeight))) | |
981 | + | else { | |
982 | + | let withdrawBlockChainId = withdrawBlockMeta._5 | |
983 | + | let isMainChain = (withdrawBlockChainId == mainChainId) | |
984 | + | let relatesToMainChain = match getInteger(chainForkedHeightKey(withdrawBlockChainId)) { | |
985 | + | case forkedHeight: Int => | |
986 | + | (forkedHeight > withdrawBlockHeight) | |
987 | + | case _ => | |
988 | + | throw((((blockHashHex + " is on an alternative chain #") + toString(withdrawBlockChainId)) + " that was not approved by majority. Wait for some blocks")) | |
989 | + | } | |
990 | + | if (if (isMainChain) | |
991 | + | then true | |
992 | + | else relatesToMainChain) | |
993 | + | then { | |
994 | + | let recipient = i.originCaller | |
995 | + | let recipientPkHash = take(drop(recipient.bytes, 2), PUBLIC_KEY_HASH_SIZE) | |
996 | + | let zeroAmountBytes = base58'11111111111111111111111111111111111111111111' | |
997 | + | let amountBytes = toBytes(amount) | |
998 | + | let elEventData = ((recipientPkHash + take(zeroAmountBytes, (size(zeroAmountBytes) - size(amountBytes)))) + amountBytes) | |
999 | + | let elEventDataDigest = blake2b256_16Kb(elEventData) | |
1000 | + | let calculatedRootHash = createMerkleRoot(merkleProof, elEventDataDigest, transferIndexInBlock) | |
1001 | + | let expectedRootHash = withdrawBlockMeta._6 | |
1002 | + | if ((calculatedRootHash == expectedRootHash)) | |
1003 | + | then { | |
1004 | + | let tokenId = fromBase58String(getStringValue(tokenIdKey)) | |
1005 | + | let transfersKey = blockElToClTransfersKey(blockHashHex) | |
1006 | + | [Reissue(tokenId, amount, true), ScriptTransfer(recipient, amount, tokenId), StringEntry(transfersKey, setOrFail(valueOrElse(getString(transfersKey), ""), transferIndexInBlock))] | |
1007 | + | } | |
1008 | + | else throw(((((("Expected root hash: " + toBase16String(expectedRootHash)) + ", got: ") + toBase16String(calculatedRootHash)) + ". Event data digest: ") + toBase64String(elEventDataDigest))) | |
1009 | + | } | |
1010 | + | else throw((("Expected " + blockHashHex) + " to be either on the main chain or relate to it")) | |
1011 | + | } | |
1012 | + | } | |
1013 | + | else throw("Strict value is not equal to itself.") | |
1014 | + | } | |
1015 | + | ||
1016 | + | ||
1017 | + | ||
1018 | + | @Callable(i) | |
1019 | + | func setup (genesisBlockHashHex,minerRewardInGwei,stakingContractAddressB58,elBridgeAddressHex) = if (isContractSetup()) | |
675 | 1020 | then throw("The contract has been already set up") | |
1021 | + | else if ((0 > minerRewardInGwei)) | |
1022 | + | then throw("The miner reward must be nonnegative") | |
1023 | + | else { | |
1024 | + | let genesisBlockHash = fromBase16String(genesisBlockHashHex) | |
1025 | + | let emptyPk = base58'11111111111111111111111111111111' | |
1026 | + | let genesisMinerAddress = addressFromPublicKey(emptyPk) | |
1027 | + | let genesisEthRewardAddress = base58'11111111111111111111' | |
1028 | + | let genesisBlockReferenceHash = "0000000000000000000000000000000000000000000000000000000000000000" | |
1029 | + | let issue = Issue("UNIT0", "Native token", 0, 8, true) | |
1030 | + | let tokenId = calculateAssetId(issue) | |
1031 | + | [mkBlockMetaEntry(genesisBlockHashHex, 0, genesisBlockReferenceHash, genesisMinerAddress, mainChainId, ""), StringEntry(chainFirstBlockIdKey(0), genesisBlockHashHex), StringEntry(chainMetaKey(0), ("0," + genesisBlockHashHex)), IntegerEntry(minerRewardKey, minerRewardInGwei), StringEntry(stakingContractAddressKey, stakingContractAddressB58), StringEntry(epochMetaKey(height), ((toString(genesisMinerAddress) + ",0,") + genesisBlockHashHex)), StringEntry(finalizedBlockKey, genesisBlockHashHex), IntegerEntry(prevRandaoHeightKey, 0), IntegerEntry(elToClTransfersEpochKey, 0), issue, StringEntry(tokenIdKey, toBase58String(tokenId)), StringEntry(elBridgeAddressKey, ("0x" + elBridgeAddressHex))] | |
1032 | + | } | |
1033 | + | ||
1034 | + | ||
1035 | + | ||
1036 | + | @Callable(i) | |
1037 | + | func setupElToClTransfers (activationHeight,elBridgeAddressHex) = if (isDefined(getInteger(elToClTransfersEpochKey))) | |
1038 | + | then throw("EL to CL transfers feature was set up") | |
676 | 1039 | else { | |
677 | - | let genesisBlockHash = fromBase16String(genesisBlockHashHex) | |
678 | - | let emptyPk = base58'11111111111111111111111111111111' | |
679 | - | let genesisMinerAddress = addressFromPublicKey(emptyPk) | |
680 | - | let genesisEthRewardAddress = base58'11111111111111111111' | |
681 | - | let genesisBlockReferenceHash = base58'11111111111111111111111111111111' | |
682 | - | let genesisBlockMeta = (((toBytes(0) + toBytes(height)) + genesisBlockReferenceHash) + genesisMinerAddress.bytes) | |
683 | - | [BinaryEntry((blockMetaK + genesisBlockHashHex), genesisBlockMeta), StringEntry(chainFirstBlockIdKey(0), genesisBlockHashHex), StringEntry(chainMetaKey(0), ("0," + genesisBlockHashHex)), IntegerEntry(minerRewardKey, minerReward), StringEntry(stakingContractAddressKey, stakingContractAddressB58), StringEntry(epochMetaKey(height), ((toString(genesisMinerAddress) + ",0,") + genesisBlockHashHex)), StringEntry(finalizedBlockKey, genesisBlockHashHex)] | |
1040 | + | let issue = Issue("UNIT0", "Native token", 0, 8, true) | |
1041 | + | let tokenId = calculateAssetId(issue) | |
1042 | + | [IntegerEntry(elToClTransfersEpochKey, activationHeight), issue, StringEntry(tokenIdKey, toBase58String(tokenId)), StringEntry(elBridgeAddressKey, ("0x" + elBridgeAddressHex))] | |
684 | 1043 | } | |
685 | 1044 | ||
686 | 1045 |
github/deemru/w8io/026f985 139.03 ms ◑