tx · xnYL9g17m4sTjSP8JEK3CgbfaRPrevXY7fUYC4vtnyu

3MsqKJ6o1ABE37676cHHBxJRs6huYTt72ch:  -0.02400000 Waves

2024.07.01 15:08 [3174859] smart account 3MsqKJ6o1ABE37676cHHBxJRs6huYTt72ch > SELF 0.00000000 Waves

{ "type": 13, "id": "xnYL9g17m4sTjSP8JEK3CgbfaRPrevXY7fUYC4vtnyu", "fee": 2400000, "feeAssetId": null, "timestamp": 1719835732964, "version": 2, "chainId": 84, "sender": "3MsqKJ6o1ABE37676cHHBxJRs6huYTt72ch", "senderPublicKey": "3xjN6fjYDXBGUE1mcRw2Fvr4R6tEZnuJA98QFGF99sXd", "proofs": [ "2zXnXB8JPxzhycdmCmvGU7bKvCZHK2QbAP4beSNYXG4HQAjfh8DKvtG9YpLASszt1uHnEZ7t2zJNTvRV8phPDV3e" ], "script": "base64:CAIsCAISBAoCCAgSBQoDCAgBEgUKAwgIARIGCgQBCAgBEgMKAQISABIFCgMIAQg/AAdJTlRfTUFYAP//////////fwAFV0FWRVMAgMLXLwALTUlOX0JBTEFOQ0UJAGgCAKCcAQUFV0FWRVMAA1NFUAIBLAAPQkxPQ0tfSEFTSF9TSVpFACAADEFERFJFU1NfU0laRQAaABB0aGlzRXBvY2hEYXRhS2V5Ag10aGlzRXBvY2hEYXRhAAxhbGxNaW5lcnNLZXkCCWFsbE1pbmVycwAObWFpbkNoYWluSWRLZXkCC21haW5DaGFpbklkAA5sYXN0Q2hhaW5JZEtleQILbGFzdENoYWluSWQAF2ZpcnN0VmFsaWRBbHRDaGFpbklkS2V5AhRmaXJzdFZhbGlkQWx0Q2hhaW5JZAAObWluZXJSZXdhcmRLZXkCC21pbmVyUmV3YXJkABlzdGFraW5nQ29udHJhY3RBZGRyZXNzS2V5AhZzdGFraW5nQ29udHJhY3RBZGRyZXNzAApibG9ja01ldGFLAghibG9ja18weAARZmluYWxpemVkQmxvY2tLZXkCDmZpbmFsaXplZEJsb2NrAQNwYWQBAWkEAXMJAKQDAQUBaQQHJG1hdGNoMAkAsQIBBQFzAwkAAAIAAQUHJG1hdGNoMAkArAICAgcwMDAwMDAwBQFzAwkAAAIAAgUHJG1hdGNoMAkArAICAgYwMDAwMDAFAXMDCQAAAgADBQckbWF0Y2gwCQCsAgICBTAwMDAwBQFzAwkAAAIABAUHJG1hdGNoMAkArAICAgQwMDAwBQFzAwkAAAIABQUHJG1hdGNoMAkArAICAgMwMDAFAXMDCQAAAgAGBQckbWF0Y2gwCQCsAgICAjAwBQFzAwkAAAIABwUHJG1hdGNoMAkArAICAgEwBQFzBQFzAQxlcG9jaE1ldGFLZXkBBWVwb2NoCQCsAgICBmVwb2NoXwkBA3BhZAEFBWVwb2NoARRjaGFpbkZpcnN0QmxvY2tJZEtleQEHY2hhaW5JZAkArAICCQCsAgICBWNoYWluCQCkAwEFB2NoYWluSWQCCkZpcnN0QmxvY2sBDGNoYWluTWV0YUtleQEHY2hhaW5JZAkArAICAgZjaGFpbl8JAQNwYWQBBQdjaGFpbklkARJjaGFpbkxhc3RIZWlnaHRLZXkCB2NoYWluSWQFbWluZXIJAKwCAgkArAICCQCsAgICBmNoYWluXwkBA3BhZAEFB2NoYWluSWQCAV8JAKUIAQUFbWluZXIBDXN1cHBvcnRlcnNLZXkBB2NoYWluSWQJAKwCAgkArAICAgVjaGFpbgkApAMBBQdjaGFpbklkAgpTdXBwb3J0ZXJzARVtaW5lclJld2FyZEFkZHJlc3NLZXkBCW1pbmVyQWRkcgkArAICCQCsAgICBm1pbmVyXwUJbWluZXJBZGRyAg5fUmV3YXJkQWRkcmVzcwEKbWluZXJQa0tleQENcmV3YXJkQWRkcmVzcwkArAICCQCsAgICCG1pbmVyXzB4BQ1yZXdhcmRBZGRyZXNzAgNfUEsBD21pbmVyQ2hhaW5JZEtleQEFbWluZXIJAKwCAgkArAICAgZtaW5lcl8JAKUIAQUFbWluZXICCF9DaGFpbklkABZzdGFraW5nQ29udHJhY3RBZGRyZXNzBAckbWF0Y2gwCQCdCAIFBHRoaXMFGXN0YWtpbmdDb250cmFjdEFkZHJlc3NLZXkDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwCQETdmFsdWVPckVycm9yTWVzc2FnZQIJAKYIAQUBcwkArAICAiJpbnZhbGlkIHN0YWtpbmcgY29udHJhY3QgYWRkcmVzczogBQFzCQEHQWRkcmVzcwEJARFAZXh0ck5hdGl2ZSgxMDUyKQIFBHRoaXMFGXN0YWtpbmdDb250cmFjdEFkZHJlc3NLZXkBEWdlbmVyYXRpbmdCYWxhbmNlAQdhZGRyZXNzBAckbWF0Y2gwCQCdCAIFFnN0YWtpbmdDb250cmFjdEFkZHJlc3MJAKwCAgIEJXNfXwkApQgBBQdhZGRyZXNzAwkAAQIFByRtYXRjaDACBlN0cmluZwQDc3RyBQckbWF0Y2gwBAlwYXJhbUxpc3QJALUJAgUDc3RyAgJfXwQKcHJldkhlaWdodAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCXBhcmFtTGlzdAABBAtwcmV2QmFsYW5jZQkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCXBhcmFtTGlzdAACBApuZXh0SGVpZ2h0CQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUJcGFyYW1MaXN0AAMEC25leHRCYWxhbmNlCQENcGFyc2VJbnRWYWx1ZQEJAJEDAgUJcGFyYW1MaXN0AAQDCQBnAgUGaGVpZ2h0BQpuZXh0SGVpZ2h0BQtuZXh0QmFsYW5jZQMJAGcCBQZoZWlnaHQFCnByZXZIZWlnaHQFC3ByZXZCYWxhbmNlAAAAAAEJY2hhaW5NZXRhAQdjaGFpbklkBAFzCQERQGV4dHJOYXRpdmUoMTA1OCkBCQEMY2hhaW5NZXRhS2V5AQUHY2hhaW5JZAQFaXRlbXMJALUJAgUBcwUDU0VQCQCUCgIJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQVpdGVtcwAACQCRAwIFBWl0ZW1zAAEAC21haW5DaGFpbklkCQELdmFsdWVPckVsc2UCCQCfCAEFDm1haW5DaGFpbklkS2V5AAAACyR0MDI4MjkyODk1CQEJY2hhaW5NZXRhAQULbWFpbkNoYWluSWQAD21haW5DaGFpbkhlaWdodAgFCyR0MDI4MjkyODk1Al8xABJtYWluQ2hhaW5MYXN0QmxvY2sIBQskdDAyODI5Mjg5NQJfMgEJZXBvY2hNZXRhAQVlcG9jaAQHJG1hdGNoMAkAoggBCQEMZXBvY2hNZXRhS2V5AQUFZXBvY2gDCQABAgUHJG1hdGNoMAIGU3RyaW5nBAFzBQckbWF0Y2gwBAlmcmFnbWVudHMJALUJAgUBcwUDU0VQCQCVCgMJARFAZXh0ck5hdGl2ZSgxMDYyKQEJAJEDAgUJZnJhZ21lbnRzAAAJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQlmcmFnbWVudHMAAQkAkQMCBQlmcmFnbWVudHMAAgUEdW5pdAALJHQwMzEyNzM1OTEEByRtYXRjaDAJAQllcG9jaE1ldGEBBQZoZWlnaHQDCQABAgUHJG1hdGNoMAIWKEFkZHJlc3MsIEludCwgU3RyaW5nKQQBbQUHJG1hdGNoMAUBbQQHJG1hdGNoMQkAoggBBRB0aGlzRXBvY2hEYXRhS2V5AwkAAQIFByRtYXRjaDECBlN0cmluZwQQcmF3VGhpc0Vwb2NoRGF0YQUHJG1hdGNoMQQNdGhpc0Vwb2NoRGF0YQkAtQkCBRByYXdUaGlzRXBvY2hEYXRhBQNTRVAECXRoaXNFcG9jaAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFDXRoaXNFcG9jaERhdGEAAAkAlQoDAwkAAAIFCXRoaXNFcG9jaAUGaGVpZ2h0CQERQGV4dHJOYXRpdmUoMTA2MikBCQCRAwIFDXRoaXNFcG9jaERhdGEAAQUEdW5pdAAAAgAJAJUKAwUEdW5pdAAAAgAADnRoaXNFcG9jaE1pbmVyCAULJHQwMzEyNzM1OTECXzEADHRoaXNFcG9jaFJlZggFCyR0MDMxMjczNTkxAl8yABJ0aGlzRXBvY2hMYXN0QmxvY2sIBQskdDAzMTI3MzU5MQJfMwAMYWxsTWluZXJzU3RyCQELdmFsdWVPckVsc2UCCQCiCAEFDGFsbE1pbmVyc0tleQIAAAlhbGxNaW5lcnMEByRtYXRjaDAFDGFsbE1pbmVyc1N0cgMJAAACAgAFByRtYXRjaDAFA25pbAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEA3JhdwUHJG1hdGNoMAkAvAkCBQNyYXcFA1NFUAkAAgECC01hdGNoIGVycm9yAQlibG9ja01ldGEBB2Jsb2NrSWQEBG1ldGEJARFAZXh0ck5hdGl2ZSgxMDU3KQEJAKwCAgUKYmxvY2tNZXRhSwUHYmxvY2tJZAQLYmxvY2tIZWlnaHQJALEJAQUEbWV0YQQKYmxvY2tFcG9jaAkAsgkCBQRtZXRhAAgEC2Jsb2NrUGFyZW50CQDJAQIJAMoBAgUEbWV0YQAQBQ9CTE9DS19IQVNIX1NJWkUEDmJsb2NrR2VuZXJhdG9yCQDMAQIFBG1ldGEFDEFERFJFU1NfU0laRQkAlgoEBQtibG9ja0hlaWdodAUKYmxvY2tFcG9jaAULYmxvY2tQYXJlbnQFDmJsb2NrR2VuZXJhdG9yAQxsYXN0SGVpZ2h0QnkCBW1pbmVyB2NoYWluSWQEByRtYXRjaDAJAJ8IAQkBEmNoYWluTGFzdEhlaWdodEtleQIFB2NoYWluSWQFBW1pbmVyAwkAAQIFByRtYXRjaDACA0ludAQBaAUHJG1hdGNoMAUBaAQJYmxvY2tIYXNoCQERQGV4dHJOYXRpdmUoMTA1OCkBCQCsAgIJAKwCAgkArAICAgVjaGFpbgkApAMBBQdjaGFpbklkAgtMYXN0TWluZWRCeQkApQgBBQVtaW5lcggJAQlibG9ja01ldGEBBQlibG9ja0hhc2gCXzEACyR0MDQzNTE1MzE3BAloaXRTb3VyY2UEByRtYXRjaDAIBQlsYXN0QmxvY2sDdnJmAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEA3ZyZgUHJG1hdGNoMAUDdnJmCAUJbGFzdEJsb2NrE2dlbmVyYXRpb25TaWduYXR1cmUKAQxwcm9jZXNzTWluZXICBHByZXYFbWluZXIECyR0MDQ2NDk0NzEyBQRwcmV2BAlwcmV2RGVsYXkIBQskdDA0NjQ5NDcxMgJfMQQJcHJldk1pbmVyCAULJHQwNDY0OTQ3MTICXzIEEHByZXZUb3RhbEJhbGFuY2UIBQskdDA0NjQ5NDcxMgJfMwQKcHJldk1pbmVycwgFCyR0MDQ2NDk0NzEyAl80BAxtaW5lckFkZHJlc3MJARFAZXh0ck5hdGl2ZSgxMDYyKQEFBW1pbmVyBA93YXZlc0dlbkJhbGFuY2UICQDvBwEFDG1pbmVyQWRkcmVzcwpnZW5lcmF0aW5nBAxtaW5lckJhbGFuY2UJARFnZW5lcmF0aW5nQmFsYW5jZQEFDG1pbmVyQWRkcmVzcwMDCQBmAgULTUlOX0JBTEFOQ0UFD3dhdmVzR2VuQmFsYW5jZQYJAGcCAAAFDG1pbmVyQmFsYW5jZQUEcHJldgQJbmV4dERlbGF5CQCFBwIFDG1pbmVyQWRkcmVzcwUMbWluZXJCYWxhbmNlAwkAZgIFCXByZXZEZWxheQUJbmV4dERlbGF5CQCWCgQFCW5leHREZWxheQUFbWluZXIJAGQCBRBwcmV2VG90YWxCYWxhbmNlBQxtaW5lckJhbGFuY2UJAM0IAgUKcHJldk1pbmVycwUFbWluZXIJAJYKBAUJcHJldkRlbGF5BQlwcmV2TWluZXIJAGQCBRBwcmV2VG90YWxCYWxhbmNlBQxtaW5lckJhbGFuY2UJAM0IAgUKcHJldk1pbmVycwUFbWluZXIKAAIkbAUJYWxsTWluZXJzCgACJHMJAJADAQUCJGwKAAUkYWNjMAkAlgoEBQdJTlRfTUFYAgAAAAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQxwcm9jZXNzTWluZXICBQIkYQkAkQMCBQIkbAUCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECFExpc3Qgc2l6ZSBleGNlZWRzIDUwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgANY29tcHV0ZWREZWxheQgFCyR0MDQzNTE1MzE3Al8xABFjb21wdXRlZEdlbmVyYXRvcggFCyR0MDQzNTE1MzE3Al8yABRjb21wdXRlZFRvdGFsQmFsYW5jZQgFCyR0MDQzNTE1MzE3Al8zAA5maWx0ZXJlZE1pbmVycwgFCyR0MDQzNTE1MzE3Al80ARNnZXRDaGFpbkxhc3RCbG9ja0lkAQdjaGFpbklkCAkBCWNoYWluTWV0YQEFB2NoYWluSWQCXzIACyR0MDUzODM1NDg1CQEJYmxvY2tNZXRhAQUSbWFpbkNoYWluTGFzdEJsb2NrAAdpZ25vcmVkCAULJHQwNTM4MzU0ODUCXzEADm1haW5DaGFpbkVwb2NoCAULJHQwNTM4MzU0ODUCXzIAE21haW5DaGFpblBhcmVudEhhc2gIBQskdDA1MzgzNTQ4NQJfMwASbWFpbkNoYWluR2VuZXJhdG9yCAULJHQwNTM4MzU0ODUCXzQBG2NhbGN1bGF0ZUZpbmFsaXplZEJsb2NrSGFzaAMIY3VyTWluZXIMY3VyUHJldkVwb2NoEGN1ckxhc3RCbG9ja0hhc2gEC29mZnNldHNfMTAwCQC8CQICZDo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoCAAQLaGFsZkJhbGFuY2UJAGkCBRRjb21wdXRlZFRvdGFsQmFsYW5jZQACCgEEc3RlcAIEcHJldgRuZXh0BAskdDA1ODUxNTkxNQUEcHJldgQJdGhpc0Vwb2NoCAULJHQwNTg1MTU5MTUCXzEEDHRvdGFsQmFsYW5jZQgFCyR0MDU4NTE1OTE1Al8yBA5tYXliZVNhZmVFcG9jaAgFCyR0MDU4NTE1OTE1Al8zBApwcmV2TWluZXJzCAULJHQwNTg1MTU5MTUCXzQEByRtYXRjaDAFDm1heWJlU2FmZUVwb2NoAwkAAQIFByRtYXRjaDACBFVuaXQECyR0MDU5NzM2MTM5AwkAAAIFCXRoaXNFcG9jaAUGaGVpZ2h0CQCVCgMFCGN1ck1pbmVyBQxjdXJQcmV2RXBvY2gFEGN1ckxhc3RCbG9ja0hhc2gJAQV2YWx1ZQEJAQllcG9jaE1ldGEBBQl0aGlzRXBvY2gEBW1pbmVyCAULJHQwNTk3MzYxMzkCXzEECXByZXZFcG9jaAgFCyR0MDU5NzM2MTM5Al8yBA1sYXN0QmxvY2tIYXNoCAULJHQwNTk3MzYxMzkCXzMDCQAAAgUJcHJldkVwb2NoAAAJAJYKBAUJdGhpc0Vwb2NoBQx0b3RhbEJhbGFuY2UFDWxhc3RCbG9ja0hhc2gFCWFsbE1pbmVycwQLJHQwNjI2NDY0NjYDCQEPY29udGFpbnNFbGVtZW50AgUKcHJldk1pbmVycwUFbWluZXIJAJQKAgUMdG90YWxCYWxhbmNlBQpwcmV2TWluZXJzCQCUCgIJAGQCBQx0b3RhbEJhbGFuY2UJARFnZW5lcmF0aW5nQmFsYW5jZQEFBW1pbmVyCQDMCAIFBW1pbmVyBQpwcmV2TWluZXJzBA9uZXdUb3RhbEJhbGFuY2UIBQskdDA2MjY0NjQ2NgJfMQQJbmV3TWluZXJzCAULJHQwNjI2NDY0NjYCXzIDCQBmAgUPbmV3VG90YWxCYWxhbmNlBQtoYWxmQmFsYW5jZQkAlgoEBQl0aGlzRXBvY2gFD25ld1RvdGFsQmFsYW5jZQUNbGFzdEJsb2NrSGFzaAUJYWxsTWluZXJzCQCWCgQFCXByZXZFcG9jaAUPbmV3VG90YWxCYWxhbmNlBQR1bml0BQluZXdNaW5lcnMFBHByZXYEA3JlcwoAAiRsCQDOCAIFC29mZnNldHNfMTAwBQtvZmZzZXRzXzEwMAoAAiRzCQCQAwEFAiRsCgAFJGFjYzAJAJYKBAUGaGVpZ2h0AAAFBHVuaXQFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEEc3RlcAIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIVTGlzdCBzaXplIGV4Y2VlZHMgMjAwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgA/AEAAQQBCAEMARABFAEYARwBIAEkASgBLAEwATQBOAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAF4AXwBgAGEAYgBjAGQAZQBmAGcAaABpAGoAawBsAG0AbgBvAHAAcQByAHMAdAB1AHYAdwB4AHkAegB7AHwAfQB+AH8AgAEAgQEAggEAgwEAhAEAhQEAhgEAhwEAiAEAiQEAigEAiwEAjAEAjQEAjgEAjwEAkAEAkQEAkgEAkwEAlAEAlQEAlgEAlwEAmAEAmQEAmgEAmwEAnAEAnQEAngEAnwEAoAEAoQEAogEAowEApAEApQEApgEApwEAqAEAqQEAqgEAqwEArAEArQEArgEArwEAsAEAsQEAsgEAswEAtAEAtQEAtgEAtwEAuAEAuQEAugEAuwEAvAEAvQEAvgEAvwEAwAEAwQEAwgEAwwEAxAEAxQEAxgEAxwEAyAEEDWZhbGxiYWNrRXBvY2gIBQNyZXMCXzEJAQt2YWx1ZU9yRWxzZQIIBQNyZXMCXzMICQEFdmFsdWUBCQEJZXBvY2hNZXRhAQUNZmFsbGJhY2tFcG9jaAJfMwERc3VwcG9ydGluZ0JhbGFuY2UBB2NoYWluSWQKAQphZGRCYWxhbmNlAgNhY2MMZ2VuZXJhdG9yU3RyBAskdDA2OTgyNzAxOAUDYWNjBAx0b3RhbEJhbGFuY2UIBQskdDA2OTgyNzAxOAJfMQQKZ2VuZXJhdG9ycwgFCyR0MDY5ODI3MDE4Al8yBAlnZW5lcmF0b3IJARFAZXh0ck5hdGl2ZSgxMDYyKQEFDGdlbmVyYXRvclN0cgMJAQ9jb250YWluc0VsZW1lbnQCBQpnZW5lcmF0b3JzBQlnZW5lcmF0b3IFA2FjYwQHYmFsYW5jZQkBEWdlbmVyYXRpbmdCYWxhbmNlAQUJZ2VuZXJhdG9yCQCUCgIJAGQCBQx0b3RhbEJhbGFuY2UFB2JhbGFuY2UJAM0IAgUKZ2VuZXJhdG9ycwUJZ2VuZXJhdG9yBA1hbGxHZW5lcmF0b3JzCQC8CQIJARFAZXh0ck5hdGl2ZSgxMDU4KQEJAQ1zdXBwb3J0ZXJzS2V5AQUHY2hhaW5JZAUDU0VQBAskdDA3MzQwNzQwNQoAAiRsBQ1hbGxHZW5lcmF0b3JzCgACJHMJAJADAQUCJGwKAAUkYWNjMAkAlAoCAAAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEKYWRkQmFsYW5jZQIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIVTGlzdCBzaXplIGV4Y2VlZHMgMTAwCQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAGAAcACAAJAAoACwAMAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgA/AEAAQQBCAEMARABFAEYARwBIAEkASgBLAEwATQBOAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAF4AXwBgAGEAYgBjAGQEB2JhbGFuY2UIBQskdDA3MzQwNzQwNQJfMQQCX2cIBQskdDA3MzQwNzQwNQJfMgUHYmFsYW5jZQEPaXNDb250cmFjdFNldHVwAAkBCWlzRGVmaW5lZAEJAJ8IAQUObWluZXJSZXdhcmRLZXkBEWVuc3VyZU1pbmluZ0Vwb2NoAQlnZW5lcmF0b3IDCQECIT0CCQClCAEFCWdlbmVyYXRvcgURY29tcHV0ZWRHZW5lcmF0b3IJAAIBCQCsAgIJAKwCAgkArAICCQCsAgIJANgEAQgFCWdlbmVyYXRvcgVieXRlcwIbIGlzIG5vdCBhbGxvd2VkIHRvIG1pbmUgaW4gCQCkAwEFBmhlaWdodAIRIGVwb2NoLiBFeHBlY3RlZCAFEWNvbXB1dGVkR2VuZXJhdG9yBQR1bml0ARJpc1JlZmVyZW5jZUNvcnJlY3QCCXJlZmVyZW5jZQlsYXN0QmxvY2sDCQAAAgUJcmVmZXJlbmNlBQlsYXN0QmxvY2sFBHVuaXQJAAIBCQCsAgIJAKwCAgkArAICAjBFeHBlY3RlZCBhIHJlZmVyZW5jZSB0byB0aGUgY2hhaW4gbGFzdCBibG9jazogMHgFCWxhc3RCbG9jawIJLiBHb3Q6IDB4BQlyZWZlcmVuY2UBD2NoYWluSXNJbmFjdGl2ZQEHY2hhaW5JZAQMZmlyc3RCbG9ja0lkCQERQGV4dHJOYXRpdmUoMTA1OCkBCQEUY2hhaW5GaXJzdEJsb2NrSWRLZXkBBQdjaGFpbklkBBRmaXJzdFZhbGlkQWx0Q2hhaW5JZAkBC3ZhbHVlT3JFbHNlAgkAnwgBBRdmaXJzdFZhbGlkQWx0Q2hhaW5JZEtleQAAAwkAZgIFFGZpcnN0VmFsaWRBbHRDaGFpbklkBQdjaGFpbklkBgkAZgIICQEJYmxvY2tNZXRhAQkBEUBleHRyTmF0aXZlKDEwNTgpAQURZmluYWxpemVkQmxvY2tLZXkCXzEICQEJYmxvY2tNZXRhAQUMZmlyc3RCbG9ja0lkAl8xAQxtaW5lckNoYWluSWQBBW1pbmVyCQELdmFsdWVPckVsc2UCCQCfCAEJAQ9taW5lckNoYWluSWRLZXkBBQVtaW5lcgkAnwgBCQCsAgICCWNoYWluSWRPZgkApQgBBQVtaW5lcgEdZW5zdXJlRXhwZWN0ZWRPckluYWN0aXZlQ2hhaW4DCWdlbmVyYXRvcg9leHBlY3RlZENoYWluSWQQY2hlY2tIZWlnaHRCbG9jawQPaGVpZ2h0SXNDb3JyZWN0BAckbWF0Y2gwBRBjaGVja0hlaWdodEJsb2NrAwkAAQIFByRtYXRjaDACBlN0cmluZwQJYmxvY2tIYXNoBQckbWF0Y2gwBBRsYXN0TWluZWRCbG9ja0hlaWdodAkBDGxhc3RIZWlnaHRCeQIFCWdlbmVyYXRvcgULbWFpbkNoYWluSWQJAGYCCQBkAggJAQlibG9ja01ldGEBBQlibG9ja0hhc2gCXzEAAQUUbGFzdE1pbmVkQmxvY2tIZWlnaHQGBAckbWF0Y2gwCQEMbWluZXJDaGFpbklkAQUJZ2VuZXJhdG9yAwkAAQIFByRtYXRjaDACA0ludAQJY3VycmVudElkBQckbWF0Y2gwAwMJAAACBQljdXJyZW50SWQFD2V4cGVjdGVkQ2hhaW5JZAYDCQEPY2hhaW5Jc0luYWN0aXZlAQUJY3VycmVudElkBQ9oZWlnaHRJc0NvcnJlY3QHBQR1bml0CQACAQkArAICAhxtaW5lciBpcyBtaW5pbmcgb3RoZXIgY2hhaW4gCQCkAwEFCWN1cnJlbnRJZAUEdW5pdAESZW5zdXJlQ29ycmVjdEVwb2NoAQVlcG9jaAMJAAACBQVlcG9jaAUGaGVpZ2h0BQR1bml0CQACAQkArAICCQCsAgIJAKwCAgIaRXhwZWN0ZWQgYmxvY2sgZnJvbSBlcG9jaCAJAKQDAQUGaGVpZ2h0AgYuIEdvdCAJAKQDAQUFZXBvY2gBDGFkZFN1cHBvcnRlcgIHY2hhaW5JZAlnZW5lcmF0b3IEDXN1cHBvcnRlcnNTdHIJARFAZXh0ck5hdGl2ZSgxMDU4KQEJAQ1zdXBwb3J0ZXJzS2V5AQUHY2hhaW5JZAQKc3VwcG9ydGVycwkAvAkCBQ1zdXBwb3J0ZXJzU3RyBQNTRVADCQEPY29udGFpbnNFbGVtZW50AgUKc3VwcG9ydGVycwkApQgBBQlnZW5lcmF0b3IFA25pbAkAzAgCCQELU3RyaW5nRW50cnkCCQENc3VwcG9ydGVyc0tleQEFB2NoYWluSWQJAKwCAgkArAICBQ1zdXBwb3J0ZXJzU3RyBQNTRVAJAKUIAQUJZ2VuZXJhdG9yBQNuaWwBEXZhbGlkYXRlQmxvY2tIYXNoAQZoZXhTdHIEDGRlY29kZWRCeXRlcwkA3QQBBQZoZXhTdHIDCQECIT0CCQDIAQEFDGRlY29kZWRCeXRlcwAgCQACAQIXaW52YWxpZCBibG9jayBpZCBsZW5ndGgFBmhleFN0cgEdZ2V0VXBkYXRlRmluYWxpemVkQmxvY2tBY3Rpb24DBmNhbGxlcg9uZXdCbG9ja0hhc2hIZXgJcHJldkVwb2NoBBdjdXJGaW5hbGl6ZWRCbG9ja0hlaWdodAgJAQlibG9ja01ldGEBCQERQGV4dHJOYXRpdmUoMTA1OCkBBRFmaW5hbGl6ZWRCbG9ja0tleQJfMQQVbmV3RmluYWxpemVkQmxvY2tIYXNoCQEbY2FsY3VsYXRlRmluYWxpemVkQmxvY2tIYXNoAwUGY2FsbGVyBQlwcmV2RXBvY2gFD25ld0Jsb2NrSGFzaEhleAMJAAACBRVuZXdGaW5hbGl6ZWRCbG9ja0hhc2gFD25ld0Jsb2NrSGFzaEhleAkAzAgCCQELU3RyaW5nRW50cnkCBRFmaW5hbGl6ZWRCbG9ja0tleQUVbmV3RmluYWxpemVkQmxvY2tIYXNoBQNuaWwDCQBmAggJAQlibG9ja01ldGEBBRVuZXdGaW5hbGl6ZWRCbG9ja0hhc2gCXzEFF2N1ckZpbmFsaXplZEJsb2NrSGVpZ2h0CQDMCAIJAQtTdHJpbmdFbnRyeQIFEWZpbmFsaXplZEJsb2NrS2V5BRVuZXdGaW5hbGl6ZWRCbG9ja0hhc2gFA25pbAUDbmlsBwFpAQthcHBlbmRCbG9jawIMYmxvY2tIYXNoSGV4DHJlZmVyZW5jZUhleAMJAQIhPQIFDnRoaXNFcG9jaE1pbmVyCAUBaQxvcmlnaW5DYWxsZXIEByRtYXRjaDAFDnRoaXNFcG9jaE1pbmVyAwkAAQIFByRtYXRjaDACB0FkZHJlc3MECmVwb2NoTWluZXIFByRtYXRjaDAJAAIBCQCsAgICOW5vdCBhbGxvd2VkIHRvIGZvcmdlIGJsb2NrcyBpbiB0aGlzIGVwb2NoLCBleHBlY3RlZCBmcm9tIAkApQgBBQplcG9jaE1pbmVyCQACAQJAbm90IGFsbG93ZWQgdG8gZm9yZ2UgYmxvY2tzIGluIHRoaXMgZXBvY2gsIGVwb2NoIG1pbmVyIGlzIGFic2VudAQHY2hhaW5JZAkBC3ZhbHVlT3JFbHNlAgkBDG1pbmVyQ2hhaW5JZAEIBQFpDG9yaWdpbkNhbGxlcgULbWFpbkNoYWluSWQEDSR0MDEwNzExMTA3NjIJAQljaGFpbk1ldGEBBQdjaGFpbklkBAtjaGFpbkhlaWdodAgFDSR0MDEwNzExMTA3NjICXzEEC2xhc3RCbG9ja0lkCAUNJHQwMTA3MTExMDc2MgJfMgQOY2hlY2tSZWZlcmVuY2UJARJpc1JlZmVyZW5jZUNvcnJlY3QCBQxyZWZlcmVuY2VIZXgFC2xhc3RCbG9ja0lkAwkAAAIFDmNoZWNrUmVmZXJlbmNlBQ5jaGVja1JlZmVyZW5jZQQObmV3Q2hhaW5IZWlnaHQJAGQCBQtjaGFpbkhlaWdodAABBAxuZXdCbG9ja01ldGEJAMsBAgkAywECCQDLAQIJAJoDAQUObmV3Q2hhaW5IZWlnaHQJAJoDAQUGaGVpZ2h0CQDdBAEFC2xhc3RCbG9ja0lkCAgFAWkMb3JpZ2luQ2FsbGVyBWJ5dGVzBAlibG9ja0hhc2gJARF2YWxpZGF0ZUJsb2NrSGFzaAEFDGJsb2NrSGFzaEhleAkAzAgCCQELQmluYXJ5RW50cnkCCQCsAgIFCmJsb2NrTWV0YUsFDGJsb2NrSGFzaEhleAUMbmV3QmxvY2tNZXRhCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQESY2hhaW5MYXN0SGVpZ2h0S2V5AgUHY2hhaW5JZAgFAWkMb3JpZ2luQ2FsbGVyBQ5uZXdDaGFpbkhlaWdodAkAzAgCCQELU3RyaW5nRW50cnkCCQEMY2hhaW5NZXRhS2V5AQUHY2hhaW5JZAkArAICCQCsAgIJAKQDAQUObmV3Q2hhaW5IZWlnaHQFA1NFUAUMYmxvY2tIYXNoSGV4CQDMCAIJAQtTdHJpbmdFbnRyeQIJAQxlcG9jaE1ldGFLZXkBBQZoZWlnaHQJAKwCAgkArAICCQCsAgIJAKwCAgkApQgBCQEFdmFsdWUBBQ50aGlzRXBvY2hNaW5lcgUDU0VQCQCkAwEFDHRoaXNFcG9jaFJlZgUDU0VQBQxibG9ja0hhc2hIZXgFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ9leHRlbmRNYWluQ2hhaW4DDGJsb2NrSGFzaEhleAxyZWZlcmVuY2VIZXgFZXBvY2gECmNoZWNrRXBvY2gJARJlbnN1cmVDb3JyZWN0RXBvY2gBBQVlcG9jaAMJAAACBQpjaGVja0Vwb2NoBQpjaGVja0Vwb2NoBA5jaGVja0dlbmVyYXRvcgkBEWVuc3VyZU1pbmluZ0Vwb2NoAQgFAWkMb3JpZ2luQ2FsbGVyAwkAAAIFDmNoZWNrR2VuZXJhdG9yBQ5jaGVja0dlbmVyYXRvcgQKY2hlY2tDaGFpbgkBHWVuc3VyZUV4cGVjdGVkT3JJbmFjdGl2ZUNoYWluAwgFAWkMb3JpZ2luQ2FsbGVyBQttYWluQ2hhaW5JZAUEdW5pdAMJAAACBQpjaGVja0NoYWluBQpjaGVja0NoYWluBA5jaGVja1JlZmVyZW5jZQkBEmlzUmVmZXJlbmNlQ29ycmVjdAIFDHJlZmVyZW5jZUhleAUSbWFpbkNoYWluTGFzdEJsb2NrAwkAAAIFDmNoZWNrUmVmZXJlbmNlBQ5jaGVja1JlZmVyZW5jZQQNdGhpc0Vwb2NoTWV0YQQHJG1hdGNoMAkBCWVwb2NoTWV0YQEFBmhlaWdodAMJAAECBQckbWF0Y2gwAgRVbml0CQELU3RyaW5nRW50cnkCCQEMZXBvY2hNZXRhS2V5AQUGaGVpZ2h0CQCsAgIJAKwCAgkArAICCQCsAgIJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBQNTRVAJAKQDAQUObWFpbkNoYWluRXBvY2gFA1NFUAUMYmxvY2tIYXNoSGV4BAVvdGhlcgUHJG1hdGNoMAkAAgECFUVwb2NoIGFscmVhZHkgc3RhcnRlZAQUdXBkYXRlRmluYWxpemVkQmxvY2sJAR1nZXRVcGRhdGVGaW5hbGl6ZWRCbG9ja0FjdGlvbgMIBQFpDG9yaWdpbkNhbGxlcgUMYmxvY2tIYXNoSGV4BQ5tYWluQ2hhaW5FcG9jaAQObmV3Q2hhaW5IZWlnaHQJAGQCBQ9tYWluQ2hhaW5IZWlnaHQAAQQMbmV3QmxvY2tNZXRhCQDLAQIJAMsBAgkAywECCQCaAwEFDm5ld0NoYWluSGVpZ2h0CQCaAwEFBmhlaWdodAkA3QQBBRJtYWluQ2hhaW5MYXN0QmxvY2sICAUBaQxvcmlnaW5DYWxsZXIFYnl0ZXMJAM4IAgkAzAgCCQELQmluYXJ5RW50cnkCCQCsAgIFCmJsb2NrTWV0YUsFDGJsb2NrSGFzaEhleAUMbmV3QmxvY2tNZXRhCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQxjaGFpbk1ldGFLZXkBBQttYWluQ2hhaW5JZAkArAICCQCsAgIJAKQDAQUObmV3Q2hhaW5IZWlnaHQFA1NFUAUMYmxvY2tIYXNoSGV4CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEPbWluZXJDaGFpbklkS2V5AQgFAWkMb3JpZ2luQ2FsbGVyBQttYWluQ2hhaW5JZAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEmNoYWluTGFzdEhlaWdodEtleQIFC21haW5DaGFpbklkCAUBaQxvcmlnaW5DYWxsZXIFDm5ld0NoYWluSGVpZ2h0CQDMCAIFDXRoaXNFcG9jaE1ldGEFA25pbAUUdXBkYXRlRmluYWxpemVkQmxvY2sJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQENc3RhcnRBbHRDaGFpbgMMYmxvY2tIYXNoSGV4DHJlZmVyZW5jZUhleAVlcG9jaAQKY2hlY2tFcG9jaAkBEmVuc3VyZUNvcnJlY3RFcG9jaAEFBWVwb2NoAwkAAAIFCmNoZWNrRXBvY2gFCmNoZWNrRXBvY2gEDmNoZWNrR2VuZXJhdG9yCQERZW5zdXJlTWluaW5nRXBvY2gBCAUBaQxvcmlnaW5DYWxsZXIDCQAAAgUOY2hlY2tHZW5lcmF0b3IFDmNoZWNrR2VuZXJhdG9yBA0kdDAxMjk3MTEzMDQ5CQEJYmxvY2tNZXRhAQUMcmVmZXJlbmNlSGV4BA5yZWZDaGFpbkhlaWdodAgFDSR0MDEyOTcxMTMwNDkCXzEECHJlZkVwb2NoCAUNJHQwMTI5NzExMzA0OQJfMgQGcmVmUmVmCAUNJHQwMTI5NzExMzA0OQJfMwQMcmVmR2VuZXJhdG9yCAUNJHQwMTI5NzExMzA0OQJfNAQOZmluYWxpemVkRXBvY2gICQEJYmxvY2tNZXRhAQkBEUBleHRyTmF0aXZlKDEwNTgpAQURZmluYWxpemVkQmxvY2tLZXkCXzIECGVwb2NoUmVmAwkAZwIFCHJlZkVwb2NoBQ5maW5hbGl6ZWRFcG9jaAUIcmVmRXBvY2gJAAIBCQCsAgIJAKwCAgkArAICCQCsAgICI2NhbiBub3Qgc3RhcnQgYWx0IGNoYWluIGZyb20gZXBvY2ggCQCkAwEFCHJlZkVwb2NoAggsIGVwb2NoIAkApAMBBQ5maW5hbGl6ZWRFcG9jaAINIGlzIGZpbmFsaXplZAQKY2hlY2tDaGFpbgkBHWVuc3VyZUV4cGVjdGVkT3JJbmFjdGl2ZUNoYWluAwgFAWkMb3JpZ2luQ2FsbGVyBQttYWluQ2hhaW5JZAUMcmVmZXJlbmNlSGV4AwkAAAIFCmNoZWNrQ2hhaW4FCmNoZWNrQ2hhaW4ECm5ld0NoYWluSWQJAGQCCQELdmFsdWVPckVsc2UCCQCfCAEFDmxhc3RDaGFpbklkS2V5AAAAAQQPcmVmZXJlbmNlSGVpZ2h0CAkBCWJsb2NrTWV0YQEFDHJlZmVyZW5jZUhleAJfMQQObmV3Q2hhaW5IZWlnaHQJAGQCBQ9yZWZlcmVuY2VIZWlnaHQAAQQMbmV3QmxvY2tNZXRhCQDLAQIJAMsBAgkAywECCQCaAwEFDm5ld0NoYWluSGVpZ2h0CQCaAwEFBmhlaWdodAkA3QQBBQxyZWZlcmVuY2VIZXgICAUBaQxvcmlnaW5DYWxsZXIFYnl0ZXMEDXRoaXNFcG9jaE1ldGEEByRtYXRjaDAJAQllcG9jaE1ldGEBBQZoZWlnaHQDCQABAgUHJG1hdGNoMAIEVW5pdAkBC1N0cmluZ0VudHJ5AgkBDGVwb2NoTWV0YUtleQEFBmhlaWdodAkArAICCQCsAgIJAKwCAgkArAICCQClCAEIBQFpDG9yaWdpbkNhbGxlcgUDU0VQCQCkAwEFCGVwb2NoUmVmBQNTRVAFDGJsb2NrSGFzaEhleAQFb3RoZXIFByRtYXRjaDAJAAIBAhVFcG9jaCBhbHJlYWR5IHN0YXJ0ZWQJAMwIAgUNdGhpc0Vwb2NoTWV0YQkAzAgCCQELQmluYXJ5RW50cnkCCQCsAgIFCmJsb2NrTWV0YUsFDGJsb2NrSGFzaEhleAUMbmV3QmxvY2tNZXRhCQDMCAIJAQtTdHJpbmdFbnRyeQIJARRjaGFpbkZpcnN0QmxvY2tJZEtleQEFCm5ld0NoYWluSWQFDGJsb2NrSGFzaEhleAkAzAgCCQELU3RyaW5nRW50cnkCCQEMY2hhaW5NZXRhS2V5AQUKbmV3Q2hhaW5JZAkArAICCQCsAgIJAKQDAQUObmV3Q2hhaW5IZWlnaHQFA1NFUAUMYmxvY2tIYXNoSGV4CQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEPbWluZXJDaGFpbklkS2V5AQgFAWkMb3JpZ2luQ2FsbGVyBQpuZXdDaGFpbklkCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQESY2hhaW5MYXN0SGVpZ2h0S2V5AgUKbmV3Q2hhaW5JZAgFAWkMb3JpZ2luQ2FsbGVyBQ5uZXdDaGFpbkhlaWdodAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEmNoYWluTGFzdEhlaWdodEtleQIFC21haW5DaGFpbklkCAUBaQxvcmlnaW5DYWxsZXIFD3JlZmVyZW5jZUhlaWdodAkAzAgCCQELU3RyaW5nRW50cnkCCQENc3VwcG9ydGVyc0tleQEFCm5ld0NoYWluSWQJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ5sYXN0Q2hhaW5JZEtleQUKbmV3Q2hhaW5JZAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmV4dGVuZEFsdENoYWluBAdjaGFpbklkDGJsb2NrSGFzaEhleAxyZWZlcmVuY2VIZXgFZXBvY2gECmNoZWNrRXBvY2gJARJlbnN1cmVDb3JyZWN0RXBvY2gBBQVlcG9jaAMJAAACBQpjaGVja0Vwb2NoBQpjaGVja0Vwb2NoBA5jaGVja0dlbmVyYXRvcgkBEWVuc3VyZU1pbmluZ0Vwb2NoAQgFAWkMb3JpZ2luQ2FsbGVyAwkAAAIFDmNoZWNrR2VuZXJhdG9yBQ5jaGVja0dlbmVyYXRvcgQKY2hlY2tDaGFpbgkBHWVuc3VyZUV4cGVjdGVkT3JJbmFjdGl2ZUNoYWluAwgFAWkMb3JpZ2luQ2FsbGVyBQdjaGFpbklkCQDcBAEICQEJYmxvY2tNZXRhAQkBEUBleHRyTmF0aXZlKDEwNTgpAQkBFGNoYWluRmlyc3RCbG9ja0lkS2V5AQUHY2hhaW5JZAJfMwMJAAACBQpjaGVja0NoYWluBQpjaGVja0NoYWluBA0kdDAxNTIxODE1MjcyCQEJY2hhaW5NZXRhAQUHY2hhaW5JZAQLY2hhaW5IZWlnaHQIBQ0kdDAxNTIxODE1MjcyAl8xBA5jaGFpbkxhc3RCbG9jawgFDSR0MDE1MjE4MTUyNzICXzIEDmNoZWNrUmVmZXJlbmNlCQESaXNSZWZlcmVuY2VDb3JyZWN0AgUMcmVmZXJlbmNlSGV4BQ5jaGFpbkxhc3RCbG9jawMJAAACBQ5jaGVja1JlZmVyZW5jZQUOY2hlY2tSZWZlcmVuY2UEDm5ld0NoYWluSGVpZ2h0CQBkAgULY2hhaW5IZWlnaHQAAQQJcHJldkVwb2NoCAkBCWJsb2NrTWV0YQEFDHJlZmVyZW5jZUhleAJfMgQTdXBkYXRlTWFpbkNoYWluRGF0YQMJAGYCCQERc3VwcG9ydGluZ0JhbGFuY2UBBQdjaGFpbklkCQBpAgUUY29tcHV0ZWRUb3RhbEJhbGFuY2UAAgQUdXBkYXRlRmluYWxpemVkQmxvY2sJAR1nZXRVcGRhdGVGaW5hbGl6ZWRCbG9ja0FjdGlvbgMIBQFpDG9yaWdpbkNhbGxlcgUMYmxvY2tIYXNoSGV4BQlwcmV2RXBvY2gJAM4IAgkAzAgCCQEMSW50ZWdlckVudHJ5AgUObWFpbkNoYWluSWRLZXkFB2NoYWluSWQJAMwIAgkBDEludGVnZXJFbnRyeQIFF2ZpcnN0VmFsaWRBbHRDaGFpbklkS2V5CQBkAgkBC3ZhbHVlT3JFbHNlAgkAnwgBBQ5sYXN0Q2hhaW5JZEtleQAAAAEFA25pbAUUdXBkYXRlRmluYWxpemVkQmxvY2sFA25pbAQNdGhpc0Vwb2NoTWV0YQQHJG1hdGNoMAkBCWVwb2NoTWV0YQEFBmhlaWdodAMJAAECBQckbWF0Y2gwAgRVbml0CQELU3RyaW5nRW50cnkCCQEMZXBvY2hNZXRhS2V5AQUGaGVpZ2h0CQCsAgIJAKwCAgkArAICCQCsAgIJAKUIAQgFAWkMb3JpZ2luQ2FsbGVyBQNTRVAJAKQDAQUJcHJldkVwb2NoBQNTRVAFDGJsb2NrSGFzaEhleAQFb3RoZXIFByRtYXRjaDAJAAIBAhVFcG9jaCBhbHJlYWR5IHN0YXJ0ZWQEHXVwZGF0ZU1haW5DaGFpbkxhc3RNaW5lZEJsb2NrAwMJAAACBRN1cGRhdGVNYWluQ2hhaW5EYXRhBQNuaWwJAQIhPQIJAQt2YWx1ZU9yRWxzZQIJAQxtaW5lckNoYWluSWQBCAUBaQxvcmlnaW5DYWxsZXIAAAUHY2hhaW5JZAcJAMwIAgkBDEludGVnZXJFbnRyeQIJARJjaGFpbkxhc3RIZWlnaHRLZXkCBQttYWluQ2hhaW5JZAgFAWkMb3JpZ2luQ2FsbGVyCAkBCWJsb2NrTWV0YQEJARFAZXh0ck5hdGl2ZSgxMDU4KQEJARRjaGFpbkZpcnN0QmxvY2tJZEtleQEFB2NoYWluSWQCXzEFA25pbAUDbmlsBAxuZXdCbG9ja01ldGEJAMsBAgkAywECCQDLAQIJAJoDAQUObmV3Q2hhaW5IZWlnaHQJAJoDAQUGaGVpZ2h0CQDdBAEFDHJlZmVyZW5jZUhleAgIBQFpDG9yaWdpbkNhbGxlcgVieXRlcwkAzggCCQDOCAIJAM4IAgkAzAgCCQELQmluYXJ5RW50cnkCCQCsAgIFCmJsb2NrTWV0YUsFDGJsb2NrSGFzaEhleAUMbmV3QmxvY2tNZXRhCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQxjaGFpbk1ldGFLZXkBBQdjaGFpbklkCQCsAgIJAKwCAgkApAMBBQ5uZXdDaGFpbkhlaWdodAUDU0VQBQxibG9ja0hhc2hIZXgJAMwIAgUNdGhpc0Vwb2NoTWV0YQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBD21pbmVyQ2hhaW5JZEtleQEIBQFpDG9yaWdpbkNhbGxlcgUHY2hhaW5JZAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBEmNoYWluTGFzdEhlaWdodEtleQIFB2NoYWluSWQIBQFpDG9yaWdpbkNhbGxlcgUObmV3Q2hhaW5IZWlnaHQFA25pbAUTdXBkYXRlTWFpbkNoYWluRGF0YQkBDGFkZFN1cHBvcnRlcgIFB2NoYWluSWQIBQFpDG9yaWdpbkNhbGxlcgUddXBkYXRlTWFpbkNoYWluTGFzdE1pbmVkQmxvY2sJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQEEam9pbgENcmV3YXJkQWRkcmVzcwoBEmNoZWNrUmV3YXJkQWRkcmVzcwEHYWRkcmVzcwQHJG1hdGNoMAkAoQgBCQEKbWluZXJQa0tleQEFB2FkZHJlc3MDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQCcGsFByRtYXRjaDADCQAAAgUCcGsIBQFpFW9yaWdpbkNhbGxlclB1YmxpY0tleQUEdW5pdAkAAgEJAKwCAgkArAICCQCsAgICEUwyIG1pbmVyIGFkZHJlc3MgBQdhZGRyZXNzAhggaXMgYWxyZWFkeSBsaW5rZWQgd2l0aCAJANgEAQUCcGsFBHVuaXQDCQEBIQEJAQ9pc0NvbnRyYWN0U2V0dXAACQACAQIfVGhlIGNvbnRyYWN0IGhhcyBub3QgeWV0IHNldCB1cAMJAGYCBQtNSU5fQkFMQU5DRQgJAO8HAQgFAWkMb3JpZ2luQ2FsbGVyCmdlbmVyYXRpbmcJAAIBCQCsAgIJAKwCAgkArAICAiFJbnN1ZmZpY2llbnQgZ2VuZXJhdGluZyBiYWxhbmNlOiAJAKQDAQgJAO8HAQgFAWkMb3JpZ2luQ2FsbGVyCmdlbmVyYXRpbmcCDC4gUmVxdWlyZWQ6IAkApAMBBQtNSU5fQkFMQU5DRQMJAQIhPQIJAMgBAQUNcmV3YXJkQWRkcmVzcwAUCQACAQIlcmV3YXJkQWRkcmVzcyBzaG91bGQgYmUgYW4gTDIgYWRkcmVzcwMJAGcCCQCQAwEFCWFsbE1pbmVycwAyCQACAQIPdG9vIG1hbnkgbWluZXJzCgEOY2hlY2tFeGlzdGVuY2UCBmV4aXN0cwVtaW5lcgMFBmV4aXN0cwYJAAACBQVtaW5lcgkApQgBCAUBaQxvcmlnaW5DYWxsZXIEDWFscmVhZHlFeGlzdHMKAAIkbAUJYWxsTWluZXJzCgACJHMJAJADAQUCJGwKAAUkYWNjMAcKAQUkZjBfMQICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkBDmNoZWNrRXhpc3RlbmNlAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyA1MAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIDBQ1hbHJlYWR5RXhpc3RzBQNuaWwECG5ld01pbmVyCQClCAEIBQFpDG9yaWdpbkNhbGxlcgQQcmV3YXJkQWRkcmVzc0hleAkA3AQBBQ1yZXdhcmRBZGRyZXNzBAVjaGVjawkBEmNoZWNrUmV3YXJkQWRkcmVzcwEFEHJld2FyZEFkZHJlc3NIZXgDCQAAAgUFY2hlY2sFBWNoZWNrBAluZXdNaW5lcnMDCQAAAgkAkAMBBQlhbGxNaW5lcnMAAAUIbmV3TWluZXIJAKwCAgkArAICBQxhbGxNaW5lcnNTdHIFA1NFUAUIbmV3TWluZXIEGGRlbGV0ZU9sZFJld2FyZEFkZHJlc3NQawQHJG1hdGNoMAkAoggBCQEVbWluZXJSZXdhcmRBZGRyZXNzS2V5AQUIbmV3TWluZXIDCQABAgUHJG1hdGNoMAIGU3RyaW5nBApvbGRBZGRyZXNzBQckbWF0Y2gwAwkAAAIFCm9sZEFkZHJlc3MJANwEAQUNcmV3YXJkQWRkcmVzcwUDbmlsCQDMCAIJAQtEZWxldGVFbnRyeQEJAQptaW5lclBrS2V5AQUKb2xkQWRkcmVzcwUDbmlsBQNuaWwJAM4IAgkAzAgCCQELU3RyaW5nRW50cnkCBQxhbGxNaW5lcnNLZXkFCW5ld01pbmVycwkAzAgCCQELU3RyaW5nRW50cnkCCQEVbWluZXJSZXdhcmRBZGRyZXNzS2V5AQUIbmV3TWluZXIJAKwCAgICMHgFEHJld2FyZEFkZHJlc3NIZXgJAMwIAgkBC0JpbmFyeUVudHJ5AgkBCm1pbmVyUGtLZXkBBRByZXdhcmRBZGRyZXNzSGV4CAUBaRVvcmlnaW5DYWxsZXJQdWJsaWNLZXkFA25pbAUYZGVsZXRlT2xkUmV3YXJkQWRkcmVzc1BrCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBBWxlYXZlAAQMbGVhdmluZ01pbmVyCQClCAEIBQFpDG9yaWdpbkNhbGxlcgoBEHNraXBMZWF2aW5nTWluZXICA2FjYwVtaW5lcgMJAAACBQVtaW5lcgUMbGVhdmluZ01pbmVyBQNhY2MJAM0IAgUDYWNjBQVtaW5lcgQPcmVtYWluaW5nTWluZXJzCgACJGwFCWFsbE1pbmVycwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEQc2tpcExlYXZpbmdNaW5lcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgNTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyBA1yZXdhcmRBZGRyS2V5CQEVbWluZXJSZXdhcmRBZGRyZXNzS2V5AQUMbGVhdmluZ01pbmVyBBFwcmV2UmV3YXJkQWRkcmVzcwkBE3ZhbHVlT3JFcnJvck1lc3NhZ2UCCQCdCAIFBHRoaXMFDXJld2FyZEFkZHJLZXkCFm1pbmVyIGhhcyBuZXZlciBqb2luZWQDCQAAAgUOdGhpc0Vwb2NoTWluZXIIBQFpDG9yaWdpbkNhbGxlcgkAAgECHGRlc2lnbmF0ZWQgbWluZXIgY2FuJ3QgbGVhdmUJAMwIAgkBC1N0cmluZ0VudHJ5AgUMYWxsTWluZXJzS2V5CQC6CQIFD3JlbWFpbmluZ01pbmVycwUDU0VQCQDMCAIJAQtEZWxldGVFbnRyeQEFDXJld2FyZEFkZHJLZXkJAMwIAgkBC0RlbGV0ZUVudHJ5AQkBCm1pbmVyUGtLZXkBBRFwcmV2UmV3YXJkQWRkcmVzcwUDbmlsAWkBBXNldHVwAxNnZW5lc2lzQmxvY2tIYXNoSGV4C21pbmVyUmV3YXJkGXN0YWtpbmdDb250cmFjdEFkZHJlc3NCNTgDCQEPaXNDb250cmFjdFNldHVwAAkAAgECJFRoZSBjb250cmFjdCBoYXMgYmVlbiBhbHJlYWR5IHNldCB1cAQQZ2VuZXNpc0Jsb2NrSGFzaAkA3QQBBRNnZW5lc2lzQmxvY2tIYXNoSGV4BAdlbXB0eVBrASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQTZ2VuZXNpc01pbmVyQWRkcmVzcwkApwgBBQdlbXB0eVBrBBdnZW5lc2lzRXRoUmV3YXJkQWRkcmVzcwEUAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWdlbmVzaXNCbG9ja1JlZmVyZW5jZUhhc2gBIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBnZW5lc2lzQmxvY2tNZXRhCQDLAQIJAMsBAgkAywECCQCaAwEAAAkAmgMBBQZoZWlnaHQFGWdlbmVzaXNCbG9ja1JlZmVyZW5jZUhhc2gIBRNnZW5lc2lzTWluZXJBZGRyZXNzBWJ5dGVzCQDMCAIJAQtCaW5hcnlFbnRyeQIJAKwCAgUKYmxvY2tNZXRhSwUTZ2VuZXNpc0Jsb2NrSGFzaEhleAUQZ2VuZXNpc0Jsb2NrTWV0YQkAzAgCCQELU3RyaW5nRW50cnkCCQEUY2hhaW5GaXJzdEJsb2NrSWRLZXkBAAAFE2dlbmVzaXNCbG9ja0hhc2hIZXgJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDGNoYWluTWV0YUtleQEAAAkArAICAgIwLAUTZ2VuZXNpc0Jsb2NrSGFzaEhleAkAzAgCCQEMSW50ZWdlckVudHJ5AgUObWluZXJSZXdhcmRLZXkFC21pbmVyUmV3YXJkCQDMCAIJAQtTdHJpbmdFbnRyeQIFGXN0YWtpbmdDb250cmFjdEFkZHJlc3NLZXkFGXN0YWtpbmdDb250cmFjdEFkZHJlc3NCNTgJAMwIAgkBC1N0cmluZ0VudHJ5AgkBDGVwb2NoTWV0YUtleQEFBmhlaWdodAkArAICCQCsAgIJAKUIAQUTZ2VuZXNpc01pbmVyQWRkcmVzcwIDLDAsBRNnZW5lc2lzQmxvY2tIYXNoSGV4CQDMCAIJAQtTdHJpbmdFbnRyeQIFEWZpbmFsaXplZEJsb2NrS2V5BRNnZW5lc2lzQmxvY2tIYXNoSGV4BQNuaWwA9x2HkQ==", "height": 3174859, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: C2MePpLdnPhPamC3XYhk9h7F1wqr56qsB2PuHB7cYSxR Next: FNjNKot193WRkSkpK9FPbckjMik1WXVhi6NsfbDPkqLL Diff:
OldNewDifferences
2828 let stakingContractAddressKey = "stakingContractAddress"
2929
3030 let blockMetaK = "block_0x"
31+
32+let finalizedBlockKey = "finalizedBlock"
3133
3234 func pad (i) = {
3335 let s = toString(i)
109111
110112 let mainChainId = valueOrElse(getInteger(mainChainIdKey), 0)
111113
112-let $t027802846 = chainMeta(mainChainId)
114+let $t028292895 = chainMeta(mainChainId)
113115
114-let mainChainHeight = $t027802846._1
116+let mainChainHeight = $t028292895._1
115117
116-let mainChainLastBlock = $t027802846._2
118+let mainChainLastBlock = $t028292895._2
117119
118120 func epochMeta (epoch) = match getString(epochMetaKey(epoch)) {
119121 case s: String =>
124126 }
125127
126128
127-let $t030783542 = match epochMeta(height) {
129+let $t031273591 = match epochMeta(height) {
128130 case m: (Address, Int, String) =>
129131 m
130132 case _ =>
140142 }
141143 }
142144
143-let thisEpochMiner = $t030783542._1
145+let thisEpochMiner = $t031273591._1
144146
145-let thisEpochRef = $t030783542._2
147+let thisEpochRef = $t031273591._2
146148
147-let thisEpochLastBlock = $t030783542._3
149+let thisEpochLastBlock = $t031273591._3
148150
149151 let allMinersStr = valueOrElse(getString(allMinersKey), "")
150152
179181 }
180182
181183
182-let $t043025268 = {
184+let $t043515317 = {
183185 let hitSource = match lastBlock.vrf {
184186 case vrf: ByteVector =>
185187 vrf
187189 lastBlock.generationSignature
188190 }
189191 func processMiner (prev,miner) = {
190- let $t046004663 = prev
191- let prevDelay = $t046004663._1
192- let prevMiner = $t046004663._2
193- let prevTotalBalance = $t046004663._3
194- let prevMiners = $t046004663._4
192+ let $t046494712 = prev
193+ let prevDelay = $t046494712._1
194+ let prevMiner = $t046494712._2
195+ let prevTotalBalance = $t046494712._3
196+ let prevMiners = $t046494712._4
195197 let minerAddress = addressFromStringValue(miner)
196198 let wavesGenBalance = wavesBalance(minerAddress).generating
197199 let minerBalance = generatingBalance(minerAddress)
221223 $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)
222224 }
223225
224-let computedDelay = $t043025268._1
226+let computedDelay = $t043515317._1
225227
226-let computedGenerator = $t043025268._2
228+let computedGenerator = $t043515317._2
227229
228-let computedTotalBalance = $t043025268._3
230+let computedTotalBalance = $t043515317._3
229231
230-let filteredMiners = $t043025268._4
232+let filteredMiners = $t043515317._4
231233
232234 func getChainLastBlockId (chainId) = chainMeta(chainId)._2
233235
234236
235-let $t053345436 = blockMeta(mainChainLastBlock)
237+let $t053835485 = blockMeta(mainChainLastBlock)
236238
237-let ignored = $t053345436._1
239+let ignored = $t053835485._1
238240
239-let mainChainEpoch = $t053345436._2
241+let mainChainEpoch = $t053835485._2
240242
241-let mainChainParentHash = $t053345436._3
243+let mainChainParentHash = $t053835485._3
242244
243-let mainChainGenerator = $t053345436._4
245+let mainChainGenerator = $t053835485._4
244246
245-let $t054386564 = {
247+func calculateFinalizedBlockHash (curMiner,curPrevEpoch,curLastBlockHash) = {
246248 let offsets_100 = split_4C("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::", "")
247249 let halfBalance = (computedTotalBalance / 2)
248250 func step (prev,next) = {
249- let $t057545818 = prev
250- let thisEpoch = $t057545818._1
251- let totalBalance = $t057545818._2
252- let maybeSafeEpoch = $t057545818._3
253- let prevMiners = $t057545818._4
251+ let $t058515915 = prev
252+ let thisEpoch = $t058515915._1
253+ let totalBalance = $t058515915._2
254+ let maybeSafeEpoch = $t058515915._3
255+ let prevMiners = $t058515915._4
254256 match maybeSafeEpoch {
255257 case _: Unit =>
256- let $t058765944 = value(epochMeta(thisEpoch))
257- let miner = $t058765944._1
258- let prevEpoch = $t058765944._2
259- let lastBlockHash = $t058765944._3
260- let $t059536149 = if (containsElement(prevMiners, miner))
261- then $Tuple2(totalBalance, prevMiners)
262- else $Tuple2((totalBalance + generatingBalance(miner)), miner :: prevMiners)
263- let newTotalBalance = $t059536149._1
264- let newMiners = $t059536149._2
265- if ((newTotalBalance >= halfBalance))
266- then $Tuple4(thisEpoch, newTotalBalance, $Tuple2(thisEpoch, lastBlockHash), allMiners)
267- else $Tuple4(prevEpoch, newTotalBalance, unit, newMiners)
258+ let $t059736139 = if ((thisEpoch == height))
259+ then $Tuple3(curMiner, curPrevEpoch, curLastBlockHash)
260+ else value(epochMeta(thisEpoch))
261+ let miner = $t059736139._1
262+ let prevEpoch = $t059736139._2
263+ let lastBlockHash = $t059736139._3
264+ if ((prevEpoch == 0))
265+ then $Tuple4(thisEpoch, totalBalance, lastBlockHash, allMiners)
266+ else {
267+ let $t062646466 = if (containsElement(prevMiners, miner))
268+ then $Tuple2(totalBalance, prevMiners)
269+ else $Tuple2((totalBalance + generatingBalance(miner)), miner :: prevMiners)
270+ let newTotalBalance = $t062646466._1
271+ let newMiners = $t062646466._2
272+ if ((newTotalBalance > halfBalance))
273+ then $Tuple4(thisEpoch, newTotalBalance, lastBlockHash, allMiners)
274+ else $Tuple4(prevEpoch, newTotalBalance, unit, newMiners)
275+ }
268276 case _ =>
269277 prev
270278 }
273281 let res = {
274282 let $l = (offsets_100 ++ offsets_100)
275283 let $s = size($l)
276- let $acc0 = $Tuple4(mainChainEpoch, 0, unit, nil)
284+ let $acc0 = $Tuple4(height, 0, unit, nil)
277285 func $f0_1 ($a,$i) = if (($i >= $s))
278286 then $a
279287 else step($a, $l[$i])
285293 $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)
286294 }
287295 let fallbackEpoch = res._1
288- valueOrElse(res._3, $Tuple2(fallbackEpoch, value(epochMeta(fallbackEpoch))._3))
296+ valueOrElse(res._3, value(epochMeta(fallbackEpoch))._3)
289297 }
290298
291-let finalizedEpoch = $t054386564._1
292-
293-let finalizedBlockHash = $t054386564._2
294299
295300 func supportingBalance (chainId) = {
296301 func addBalance (acc,generatorStr) = {
297- let $t066826718 = acc
298- let totalBalance = $t066826718._1
299- let generators = $t066826718._2
302+ let $t069827018 = acc
303+ let totalBalance = $t069827018._1
304+ let generators = $t069827018._2
300305 let generator = addressFromStringValue(generatorStr)
301306 if (containsElement(generators, generator))
302307 then acc
307312 }
308313
309314 let allGenerators = split_4C(getStringValue(supportersKey(chainId)), SEP)
310- let $t070407105 = {
315+ let $t073407405 = {
311316 let $l = allGenerators
312317 let $s = size($l)
313318 let $acc0 = $Tuple2(0, nil)
321326
322327 $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)
323328 }
324- let balance = $t070407105._1
325- let _g = $t070407105._2
329+ let balance = $t073407405._1
330+ let _g = $t073407405._2
326331 balance
327332 }
328333
345350 let firstValidAltChainId = valueOrElse(getInteger(firstValidAltChainIdKey), 0)
346351 if ((firstValidAltChainId > chainId))
347352 then true
348- else (blockMeta(finalizedBlockHash)._1 > blockMeta(firstBlockId)._1)
353+ else (blockMeta(getStringValue(finalizedBlockKey))._1 > blockMeta(firstBlockId)._1)
349354 }
350355
351356
397402 }
398403
399404
405+func getUpdateFinalizedBlockAction (caller,newBlockHashHex,prevEpoch) = {
406+ let curFinalizedBlockHeight = blockMeta(getStringValue(finalizedBlockKey))._1
407+ let newFinalizedBlockHash = calculateFinalizedBlockHash(caller, prevEpoch, newBlockHashHex)
408+ if ((newFinalizedBlockHash == newBlockHashHex))
409+ then [StringEntry(finalizedBlockKey, newFinalizedBlockHash)]
410+ else if ((blockMeta(newFinalizedBlockHash)._1 > curFinalizedBlockHeight))
411+ then [StringEntry(finalizedBlockKey, newFinalizedBlockHash)]
412+ else nil
413+ }
414+
415+
400416 @Callable(i)
401417 func appendBlock (blockHashHex,referenceHex) = if ((thisEpochMiner != i.originCaller))
402418 then match thisEpochMiner {
407423 }
408424 else {
409425 let chainId = valueOrElse(minerChainId(i.originCaller), mainChainId)
410- let $t098649915 = chainMeta(chainId)
411- let chainHeight = $t098649915._1
412- let lastBlockId = $t098649915._2
426+ let $t01071110762 = chainMeta(chainId)
427+ let chainHeight = $t01071110762._1
428+ let lastBlockId = $t01071110762._2
413429 let checkReference = isReferenceCorrect(referenceHex, lastBlockId)
414430 if ((checkReference == checkReference))
415431 then {
443459 case other =>
444460 throw("Epoch already started")
445461 }
462+ let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, mainChainEpoch)
446463 let newChainHeight = (mainChainHeight + 1)
447464 let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(mainChainLastBlock)) + i.originCaller.bytes)
448-[BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(mainChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), mainChainId), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), thisEpochMeta]
465+ ([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(mainChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), mainChainId), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), thisEpochMeta] ++ updateFinalizedBlock)
449466 }
450467 else throw("Strict value is not equal to itself.")
451468 }
466483 let checkGenerator = ensureMiningEpoch(i.originCaller)
467484 if ((checkGenerator == checkGenerator))
468485 then {
469- let $t01199512073 = blockMeta(referenceHex)
470- let refChainHeight = $t01199512073._1
471- let refEpoch = $t01199512073._2
472- let refRef = $t01199512073._3
473- let refGenerator = $t01199512073._4
486+ let $t01297113049 = blockMeta(referenceHex)
487+ let refChainHeight = $t01297113049._1
488+ let refEpoch = $t01297113049._2
489+ let refRef = $t01297113049._3
490+ let refGenerator = $t01297113049._4
491+ let finalizedEpoch = blockMeta(getStringValue(finalizedBlockKey))._2
474492 let epochRef = if ((refEpoch >= finalizedEpoch))
475493 then refEpoch
476494 else throw((((("can not start alt chain from epoch " + toString(refEpoch)) + ", epoch ") + toString(finalizedEpoch)) + " is finalized"))
509527 let checkChain = ensureExpectedOrInactiveChain(i.originCaller, chainId, toBase16String(blockMeta(getStringValue(chainFirstBlockIdKey(chainId)))._3))
510528 if ((checkChain == checkChain))
511529 then {
512- let $t01417214226 = chainMeta(chainId)
513- let chainHeight = $t01417214226._1
514- let chainLastBlock = $t01417214226._2
530+ let $t01521815272 = chainMeta(chainId)
531+ let chainHeight = $t01521815272._1
532+ let chainLastBlock = $t01521815272._2
515533 let checkReference = isReferenceCorrect(referenceHex, chainLastBlock)
516534 if ((checkReference == checkReference))
517535 then {
518536 let newChainHeight = (chainHeight + 1)
519- let mainChainEntry = if ((supportingBalance(chainId) > (computedTotalBalance / 2)))
520- then [IntegerEntry(mainChainIdKey, chainId), IntegerEntry(firstValidAltChainIdKey, (valueOrElse(getInteger(lastChainIdKey), 0) + 1))]
537+ let prevEpoch = blockMeta(referenceHex)._2
538+ let updateMainChainData = if ((supportingBalance(chainId) > (computedTotalBalance / 2)))
539+ then {
540+ let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, prevEpoch)
541+ ([IntegerEntry(mainChainIdKey, chainId), IntegerEntry(firstValidAltChainIdKey, (valueOrElse(getInteger(lastChainIdKey), 0) + 1))] ++ updateFinalizedBlock)
542+ }
521543 else nil
522544 let thisEpochMeta = match epochMeta(height) {
523545 case _: Unit =>
524- StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(blockMeta(referenceHex)._2)) + SEP) + blockHashHex))
546+ StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(prevEpoch)) + SEP) + blockHashHex))
525547 case other =>
526548 throw("Epoch already started")
527549 }
528- let updateMainChainLastMinedBlock = if (if ((mainChainEntry == nil))
550+ let updateMainChainLastMinedBlock = if (if ((updateMainChainData == nil))
529551 then (valueOrElse(minerChainId(i.originCaller), 0) != chainId)
530552 else false)
531553 then [IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), blockMeta(getStringValue(chainFirstBlockIdKey(chainId)))._1)]
532554 else nil
533555 let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(referenceHex)) + i.originCaller.bytes)
534- ((([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), thisEpochMeta, IntegerEntry(minerChainIdKey(i.originCaller), chainId), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight)] ++ mainChainEntry) ++ addSupporter(chainId, i.originCaller)) ++ updateMainChainLastMinedBlock)
556+ ((([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)
535557 }
536558 else throw("Strict value is not equal to itself.")
537559 }
650672 let genesisEthRewardAddress = base58'11111111111111111111'
651673 let genesisBlockReferenceHash = base58'11111111111111111111111111111111'
652674 let genesisBlockMeta = (((toBytes(0) + toBytes(height)) + genesisBlockReferenceHash) + genesisMinerAddress.bytes)
653-[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))]
675+[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)]
654676 }
655677
656678
Full:
OldNewDifferences
11 {-# STDLIB_VERSION 8 #-}
22 {-# SCRIPT_TYPE ACCOUNT #-}
33 {-# CONTENT_TYPE DAPP #-}
44 let INT_MAX = 9223372036854775807
55
66 let WAVES = 100000000
77
88 let MIN_BALANCE = (20000 * WAVES)
99
1010 let SEP = ","
1111
1212 let BLOCK_HASH_SIZE = 32
1313
1414 let ADDRESS_SIZE = 26
1515
1616 let thisEpochDataKey = "thisEpochData"
1717
1818 let allMinersKey = "allMiners"
1919
2020 let mainChainIdKey = "mainChainId"
2121
2222 let lastChainIdKey = "lastChainId"
2323
2424 let firstValidAltChainIdKey = "firstValidAltChainId"
2525
2626 let minerRewardKey = "minerReward"
2727
2828 let stakingContractAddressKey = "stakingContractAddress"
2929
3030 let blockMetaK = "block_0x"
31+
32+let finalizedBlockKey = "finalizedBlock"
3133
3234 func pad (i) = {
3335 let s = toString(i)
3436 match size(s) {
3537 case _ =>
3638 if ((1 == $match0))
3739 then ("0000000" + s)
3840 else if ((2 == $match0))
3941 then ("000000" + s)
4042 else if ((3 == $match0))
4143 then ("00000" + s)
4244 else if ((4 == $match0))
4345 then ("0000" + s)
4446 else if ((5 == $match0))
4547 then ("000" + s)
4648 else if ((6 == $match0))
4749 then ("00" + s)
4850 else if ((7 == $match0))
4951 then ("0" + s)
5052 else s
5153 }
5254 }
5355
5456
5557 func epochMetaKey (epoch) = ("epoch_" + pad(epoch))
5658
5759
5860 func chainFirstBlockIdKey (chainId) = (("chain" + toString(chainId)) + "FirstBlock")
5961
6062
6163 func chainMetaKey (chainId) = ("chain_" + pad(chainId))
6264
6365
6466 func chainLastHeightKey (chainId,miner) = ((("chain_" + pad(chainId)) + "_") + toString(miner))
6567
6668
6769 func supportersKey (chainId) = (("chain" + toString(chainId)) + "Supporters")
6870
6971
7072 func minerRewardAddressKey (minerAddr) = (("miner_" + minerAddr) + "_RewardAddress")
7173
7274
7375 func minerPkKey (rewardAddress) = (("miner_0x" + rewardAddress) + "_PK")
7476
7577
7678 func minerChainIdKey (miner) = (("miner_" + toString(miner)) + "_ChainId")
7779
7880
7981 let stakingContractAddress = match getString(this, stakingContractAddressKey) {
8082 case s: String =>
8183 valueOrErrorMessage(addressFromString(s), ("invalid staking contract address: " + s))
8284 case _ =>
8385 Address(getBinaryValue(this, stakingContractAddressKey))
8486 }
8587
8688 func generatingBalance (address) = match getString(stakingContractAddress, ("%s__" + toString(address))) {
8789 case str: String =>
8890 let paramList = split(str, "__")
8991 let prevHeight = parseIntValue(paramList[1])
9092 let prevBalance = parseIntValue(paramList[2])
9193 let nextHeight = parseIntValue(paramList[3])
9294 let nextBalance = parseIntValue(paramList[4])
9395 if ((height >= nextHeight))
9496 then nextBalance
9597 else if ((height >= prevHeight))
9698 then prevBalance
9799 else 0
98100 case _ =>
99101 0
100102 }
101103
102104
103105 func chainMeta (chainId) = {
104106 let s = getStringValue(chainMetaKey(chainId))
105107 let items = split(s, SEP)
106108 $Tuple2(parseIntValue(items[0]), items[1])
107109 }
108110
109111
110112 let mainChainId = valueOrElse(getInteger(mainChainIdKey), 0)
111113
112-let $t027802846 = chainMeta(mainChainId)
114+let $t028292895 = chainMeta(mainChainId)
113115
114-let mainChainHeight = $t027802846._1
116+let mainChainHeight = $t028292895._1
115117
116-let mainChainLastBlock = $t027802846._2
118+let mainChainLastBlock = $t028292895._2
117119
118120 func epochMeta (epoch) = match getString(epochMetaKey(epoch)) {
119121 case s: String =>
120122 let fragments = split(s, SEP)
121123 $Tuple3(addressFromStringValue(fragments[0]), parseIntValue(fragments[1]), fragments[2])
122124 case _ =>
123125 unit
124126 }
125127
126128
127-let $t030783542 = match epochMeta(height) {
129+let $t031273591 = match epochMeta(height) {
128130 case m: (Address, Int, String) =>
129131 m
130132 case _ =>
131133 match getString(thisEpochDataKey) {
132134 case rawThisEpochData: String =>
133135 let thisEpochData = split(rawThisEpochData, SEP)
134136 let thisEpoch = parseIntValue(thisEpochData[0])
135137 $Tuple3(if ((thisEpoch == height))
136138 then addressFromStringValue(thisEpochData[1])
137139 else unit, 0, "")
138140 case _ =>
139141 $Tuple3(unit, 0, "")
140142 }
141143 }
142144
143-let thisEpochMiner = $t030783542._1
145+let thisEpochMiner = $t031273591._1
144146
145-let thisEpochRef = $t030783542._2
147+let thisEpochRef = $t031273591._2
146148
147-let thisEpochLastBlock = $t030783542._3
149+let thisEpochLastBlock = $t031273591._3
148150
149151 let allMinersStr = valueOrElse(getString(allMinersKey), "")
150152
151153 let allMiners = match allMinersStr {
152154 case _ =>
153155 if (("" == $match0))
154156 then nil
155157 else if ($isInstanceOf($match0, "String"))
156158 then {
157159 let raw = $match0
158160 split_4C(raw, SEP)
159161 }
160162 else throw("Match error")
161163 }
162164
163165 func blockMeta (blockId) = {
164166 let meta = getBinaryValue((blockMetaK + blockId))
165167 let blockHeight = toInt(meta)
166168 let blockEpoch = toInt(meta, 8)
167169 let blockParent = take(drop(meta, 16), BLOCK_HASH_SIZE)
168170 let blockGenerator = takeRight(meta, ADDRESS_SIZE)
169171 $Tuple4(blockHeight, blockEpoch, blockParent, blockGenerator)
170172 }
171173
172174
173175 func lastHeightBy (miner,chainId) = match getInteger(chainLastHeightKey(chainId, miner)) {
174176 case h: Int =>
175177 h
176178 case _ =>
177179 let blockHash = getStringValue(((("chain" + toString(chainId)) + "LastMinedBy") + toString(miner)))
178180 blockMeta(blockHash)._1
179181 }
180182
181183
182-let $t043025268 = {
184+let $t043515317 = {
183185 let hitSource = match lastBlock.vrf {
184186 case vrf: ByteVector =>
185187 vrf
186188 case _ =>
187189 lastBlock.generationSignature
188190 }
189191 func processMiner (prev,miner) = {
190- let $t046004663 = prev
191- let prevDelay = $t046004663._1
192- let prevMiner = $t046004663._2
193- let prevTotalBalance = $t046004663._3
194- let prevMiners = $t046004663._4
192+ let $t046494712 = prev
193+ let prevDelay = $t046494712._1
194+ let prevMiner = $t046494712._2
195+ let prevTotalBalance = $t046494712._3
196+ let prevMiners = $t046494712._4
195197 let minerAddress = addressFromStringValue(miner)
196198 let wavesGenBalance = wavesBalance(minerAddress).generating
197199 let minerBalance = generatingBalance(minerAddress)
198200 if (if ((MIN_BALANCE > wavesGenBalance))
199201 then true
200202 else (0 >= minerBalance))
201203 then prev
202204 else {
203205 let nextDelay = calculateDelay(minerAddress, minerBalance)
204206 if ((prevDelay > nextDelay))
205207 then $Tuple4(nextDelay, miner, (prevTotalBalance + minerBalance), (prevMiners :+ miner))
206208 else $Tuple4(prevDelay, prevMiner, (prevTotalBalance + minerBalance), (prevMiners :+ miner))
207209 }
208210 }
209211
210212 let $l = allMiners
211213 let $s = size($l)
212214 let $acc0 = $Tuple4(INT_MAX, "", 0, nil)
213215 func $f0_1 ($a,$i) = if (($i >= $s))
214216 then $a
215217 else processMiner($a, $l[$i])
216218
217219 func $f0_2 ($a,$i) = if (($i >= $s))
218220 then $a
219221 else throw("List size exceeds 50")
220222
221223 $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)
222224 }
223225
224-let computedDelay = $t043025268._1
226+let computedDelay = $t043515317._1
225227
226-let computedGenerator = $t043025268._2
228+let computedGenerator = $t043515317._2
227229
228-let computedTotalBalance = $t043025268._3
230+let computedTotalBalance = $t043515317._3
229231
230-let filteredMiners = $t043025268._4
232+let filteredMiners = $t043515317._4
231233
232234 func getChainLastBlockId (chainId) = chainMeta(chainId)._2
233235
234236
235-let $t053345436 = blockMeta(mainChainLastBlock)
237+let $t053835485 = blockMeta(mainChainLastBlock)
236238
237-let ignored = $t053345436._1
239+let ignored = $t053835485._1
238240
239-let mainChainEpoch = $t053345436._2
241+let mainChainEpoch = $t053835485._2
240242
241-let mainChainParentHash = $t053345436._3
243+let mainChainParentHash = $t053835485._3
242244
243-let mainChainGenerator = $t053345436._4
245+let mainChainGenerator = $t053835485._4
244246
245-let $t054386564 = {
247+func calculateFinalizedBlockHash (curMiner,curPrevEpoch,curLastBlockHash) = {
246248 let offsets_100 = split_4C("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::", "")
247249 let halfBalance = (computedTotalBalance / 2)
248250 func step (prev,next) = {
249- let $t057545818 = prev
250- let thisEpoch = $t057545818._1
251- let totalBalance = $t057545818._2
252- let maybeSafeEpoch = $t057545818._3
253- let prevMiners = $t057545818._4
251+ let $t058515915 = prev
252+ let thisEpoch = $t058515915._1
253+ let totalBalance = $t058515915._2
254+ let maybeSafeEpoch = $t058515915._3
255+ let prevMiners = $t058515915._4
254256 match maybeSafeEpoch {
255257 case _: Unit =>
256- let $t058765944 = value(epochMeta(thisEpoch))
257- let miner = $t058765944._1
258- let prevEpoch = $t058765944._2
259- let lastBlockHash = $t058765944._3
260- let $t059536149 = if (containsElement(prevMiners, miner))
261- then $Tuple2(totalBalance, prevMiners)
262- else $Tuple2((totalBalance + generatingBalance(miner)), miner :: prevMiners)
263- let newTotalBalance = $t059536149._1
264- let newMiners = $t059536149._2
265- if ((newTotalBalance >= halfBalance))
266- then $Tuple4(thisEpoch, newTotalBalance, $Tuple2(thisEpoch, lastBlockHash), allMiners)
267- else $Tuple4(prevEpoch, newTotalBalance, unit, newMiners)
258+ let $t059736139 = if ((thisEpoch == height))
259+ then $Tuple3(curMiner, curPrevEpoch, curLastBlockHash)
260+ else value(epochMeta(thisEpoch))
261+ let miner = $t059736139._1
262+ let prevEpoch = $t059736139._2
263+ let lastBlockHash = $t059736139._3
264+ if ((prevEpoch == 0))
265+ then $Tuple4(thisEpoch, totalBalance, lastBlockHash, allMiners)
266+ else {
267+ let $t062646466 = if (containsElement(prevMiners, miner))
268+ then $Tuple2(totalBalance, prevMiners)
269+ else $Tuple2((totalBalance + generatingBalance(miner)), miner :: prevMiners)
270+ let newTotalBalance = $t062646466._1
271+ let newMiners = $t062646466._2
272+ if ((newTotalBalance > halfBalance))
273+ then $Tuple4(thisEpoch, newTotalBalance, lastBlockHash, allMiners)
274+ else $Tuple4(prevEpoch, newTotalBalance, unit, newMiners)
275+ }
268276 case _ =>
269277 prev
270278 }
271279 }
272280
273281 let res = {
274282 let $l = (offsets_100 ++ offsets_100)
275283 let $s = size($l)
276- let $acc0 = $Tuple4(mainChainEpoch, 0, unit, nil)
284+ let $acc0 = $Tuple4(height, 0, unit, nil)
277285 func $f0_1 ($a,$i) = if (($i >= $s))
278286 then $a
279287 else step($a, $l[$i])
280288
281289 func $f0_2 ($a,$i) = if (($i >= $s))
282290 then $a
283291 else throw("List size exceeds 200")
284292
285293 $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)
286294 }
287295 let fallbackEpoch = res._1
288- valueOrElse(res._3, $Tuple2(fallbackEpoch, value(epochMeta(fallbackEpoch))._3))
296+ valueOrElse(res._3, value(epochMeta(fallbackEpoch))._3)
289297 }
290298
291-let finalizedEpoch = $t054386564._1
292-
293-let finalizedBlockHash = $t054386564._2
294299
295300 func supportingBalance (chainId) = {
296301 func addBalance (acc,generatorStr) = {
297- let $t066826718 = acc
298- let totalBalance = $t066826718._1
299- let generators = $t066826718._2
302+ let $t069827018 = acc
303+ let totalBalance = $t069827018._1
304+ let generators = $t069827018._2
300305 let generator = addressFromStringValue(generatorStr)
301306 if (containsElement(generators, generator))
302307 then acc
303308 else {
304309 let balance = generatingBalance(generator)
305310 $Tuple2((totalBalance + balance), (generators :+ generator))
306311 }
307312 }
308313
309314 let allGenerators = split_4C(getStringValue(supportersKey(chainId)), SEP)
310- let $t070407105 = {
315+ let $t073407405 = {
311316 let $l = allGenerators
312317 let $s = size($l)
313318 let $acc0 = $Tuple2(0, nil)
314319 func $f0_1 ($a,$i) = if (($i >= $s))
315320 then $a
316321 else addBalance($a, $l[$i])
317322
318323 func $f0_2 ($a,$i) = if (($i >= $s))
319324 then $a
320325 else throw("List size exceeds 100")
321326
322327 $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)
323328 }
324- let balance = $t070407105._1
325- let _g = $t070407105._2
329+ let balance = $t073407405._1
330+ let _g = $t073407405._2
326331 balance
327332 }
328333
329334
330335 func isContractSetup () = isDefined(getInteger(minerRewardKey))
331336
332337
333338 func ensureMiningEpoch (generator) = if ((toString(generator) != computedGenerator))
334339 then throw(((((toBase58String(generator.bytes) + " is not allowed to mine in ") + toString(height)) + " epoch. Expected ") + computedGenerator))
335340 else unit
336341
337342
338343 func isReferenceCorrect (reference,lastBlock) = if ((reference == lastBlock))
339344 then unit
340345 else throw(((("Expected a reference to the chain last block: 0x" + lastBlock) + ". Got: 0x") + reference))
341346
342347
343348 func chainIsInactive (chainId) = {
344349 let firstBlockId = getStringValue(chainFirstBlockIdKey(chainId))
345350 let firstValidAltChainId = valueOrElse(getInteger(firstValidAltChainIdKey), 0)
346351 if ((firstValidAltChainId > chainId))
347352 then true
348- else (blockMeta(finalizedBlockHash)._1 > blockMeta(firstBlockId)._1)
353+ else (blockMeta(getStringValue(finalizedBlockKey))._1 > blockMeta(firstBlockId)._1)
349354 }
350355
351356
352357 func minerChainId (miner) = valueOrElse(getInteger(minerChainIdKey(miner)), getInteger(("chainIdOf" + toString(miner))))
353358
354359
355360 func ensureExpectedOrInactiveChain (generator,expectedChainId,checkHeightBlock) = {
356361 let heightIsCorrect = match checkHeightBlock {
357362 case blockHash: String =>
358363 let lastMinedBlockHeight = lastHeightBy(generator, mainChainId)
359364 ((blockMeta(blockHash)._1 + 1) > lastMinedBlockHeight)
360365 case _ =>
361366 true
362367 }
363368 match minerChainId(generator) {
364369 case currentId: Int =>
365370 if (if ((currentId == expectedChainId))
366371 then true
367372 else if (chainIsInactive(currentId))
368373 then heightIsCorrect
369374 else false)
370375 then unit
371376 else throw(("miner is mining other chain " + toString(currentId)))
372377 case _ =>
373378 unit
374379 }
375380 }
376381
377382
378383 func ensureCorrectEpoch (epoch) = if ((epoch == height))
379384 then unit
380385 else throw(((("Expected block from epoch " + toString(height)) + ". Got ") + toString(epoch)))
381386
382387
383388 func addSupporter (chainId,generator) = {
384389 let supportersStr = getStringValue(supportersKey(chainId))
385390 let supporters = split_4C(supportersStr, SEP)
386391 if (containsElement(supporters, toString(generator)))
387392 then nil
388393 else [StringEntry(supportersKey(chainId), ((supportersStr + SEP) + toString(generator)))]
389394 }
390395
391396
392397 func validateBlockHash (hexStr) = {
393398 let decodedBytes = fromBase16String(hexStr)
394399 if ((size(decodedBytes) != 32))
395400 then throw("invalid block id length")
396401 else hexStr
397402 }
398403
399404
405+func getUpdateFinalizedBlockAction (caller,newBlockHashHex,prevEpoch) = {
406+ let curFinalizedBlockHeight = blockMeta(getStringValue(finalizedBlockKey))._1
407+ let newFinalizedBlockHash = calculateFinalizedBlockHash(caller, prevEpoch, newBlockHashHex)
408+ if ((newFinalizedBlockHash == newBlockHashHex))
409+ then [StringEntry(finalizedBlockKey, newFinalizedBlockHash)]
410+ else if ((blockMeta(newFinalizedBlockHash)._1 > curFinalizedBlockHeight))
411+ then [StringEntry(finalizedBlockKey, newFinalizedBlockHash)]
412+ else nil
413+ }
414+
415+
400416 @Callable(i)
401417 func appendBlock (blockHashHex,referenceHex) = if ((thisEpochMiner != i.originCaller))
402418 then match thisEpochMiner {
403419 case epochMiner: Address =>
404420 throw(("not allowed to forge blocks in this epoch, expected from " + toString(epochMiner)))
405421 case _ =>
406422 throw("not allowed to forge blocks in this epoch, epoch miner is absent")
407423 }
408424 else {
409425 let chainId = valueOrElse(minerChainId(i.originCaller), mainChainId)
410- let $t098649915 = chainMeta(chainId)
411- let chainHeight = $t098649915._1
412- let lastBlockId = $t098649915._2
426+ let $t01071110762 = chainMeta(chainId)
427+ let chainHeight = $t01071110762._1
428+ let lastBlockId = $t01071110762._2
413429 let checkReference = isReferenceCorrect(referenceHex, lastBlockId)
414430 if ((checkReference == checkReference))
415431 then {
416432 let newChainHeight = (chainHeight + 1)
417433 let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(lastBlockId)) + i.originCaller.bytes)
418434 let blockHash = validateBlockHash(blockHashHex)
419435 [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))]
420436 }
421437 else throw("Strict value is not equal to itself.")
422438 }
423439
424440
425441
426442 @Callable(i)
427443 func extendMainChain (blockHashHex,referenceHex,epoch) = {
428444 let checkEpoch = ensureCorrectEpoch(epoch)
429445 if ((checkEpoch == checkEpoch))
430446 then {
431447 let checkGenerator = ensureMiningEpoch(i.originCaller)
432448 if ((checkGenerator == checkGenerator))
433449 then {
434450 let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, unit)
435451 if ((checkChain == checkChain))
436452 then {
437453 let checkReference = isReferenceCorrect(referenceHex, mainChainLastBlock)
438454 if ((checkReference == checkReference))
439455 then {
440456 let thisEpochMeta = match epochMeta(height) {
441457 case _: Unit =>
442458 StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(mainChainEpoch)) + SEP) + blockHashHex))
443459 case other =>
444460 throw("Epoch already started")
445461 }
462+ let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, mainChainEpoch)
446463 let newChainHeight = (mainChainHeight + 1)
447464 let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(mainChainLastBlock)) + i.originCaller.bytes)
448-[BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(mainChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), mainChainId), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), thisEpochMeta]
465+ ([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(mainChainId), ((toString(newChainHeight) + SEP) + blockHashHex)), IntegerEntry(minerChainIdKey(i.originCaller), mainChainId), IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), newChainHeight), thisEpochMeta] ++ updateFinalizedBlock)
449466 }
450467 else throw("Strict value is not equal to itself.")
451468 }
452469 else throw("Strict value is not equal to itself.")
453470 }
454471 else throw("Strict value is not equal to itself.")
455472 }
456473 else throw("Strict value is not equal to itself.")
457474 }
458475
459476
460477
461478 @Callable(i)
462479 func startAltChain (blockHashHex,referenceHex,epoch) = {
463480 let checkEpoch = ensureCorrectEpoch(epoch)
464481 if ((checkEpoch == checkEpoch))
465482 then {
466483 let checkGenerator = ensureMiningEpoch(i.originCaller)
467484 if ((checkGenerator == checkGenerator))
468485 then {
469- let $t01199512073 = blockMeta(referenceHex)
470- let refChainHeight = $t01199512073._1
471- let refEpoch = $t01199512073._2
472- let refRef = $t01199512073._3
473- let refGenerator = $t01199512073._4
486+ let $t01297113049 = blockMeta(referenceHex)
487+ let refChainHeight = $t01297113049._1
488+ let refEpoch = $t01297113049._2
489+ let refRef = $t01297113049._3
490+ let refGenerator = $t01297113049._4
491+ let finalizedEpoch = blockMeta(getStringValue(finalizedBlockKey))._2
474492 let epochRef = if ((refEpoch >= finalizedEpoch))
475493 then refEpoch
476494 else throw((((("can not start alt chain from epoch " + toString(refEpoch)) + ", epoch ") + toString(finalizedEpoch)) + " is finalized"))
477495 let checkChain = ensureExpectedOrInactiveChain(i.originCaller, mainChainId, referenceHex)
478496 if ((checkChain == checkChain))
479497 then {
480498 let newChainId = (valueOrElse(getInteger(lastChainIdKey), 0) + 1)
481499 let referenceHeight = blockMeta(referenceHex)._1
482500 let newChainHeight = (referenceHeight + 1)
483501 let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(referenceHex)) + i.originCaller.bytes)
484502 let thisEpochMeta = match epochMeta(height) {
485503 case _: Unit =>
486504 StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(epochRef)) + SEP) + blockHashHex))
487505 case other =>
488506 throw("Epoch already started")
489507 }
490508 [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)]
491509 }
492510 else throw("Strict value is not equal to itself.")
493511 }
494512 else throw("Strict value is not equal to itself.")
495513 }
496514 else throw("Strict value is not equal to itself.")
497515 }
498516
499517
500518
501519 @Callable(i)
502520 func extendAltChain (chainId,blockHashHex,referenceHex,epoch) = {
503521 let checkEpoch = ensureCorrectEpoch(epoch)
504522 if ((checkEpoch == checkEpoch))
505523 then {
506524 let checkGenerator = ensureMiningEpoch(i.originCaller)
507525 if ((checkGenerator == checkGenerator))
508526 then {
509527 let checkChain = ensureExpectedOrInactiveChain(i.originCaller, chainId, toBase16String(blockMeta(getStringValue(chainFirstBlockIdKey(chainId)))._3))
510528 if ((checkChain == checkChain))
511529 then {
512- let $t01417214226 = chainMeta(chainId)
513- let chainHeight = $t01417214226._1
514- let chainLastBlock = $t01417214226._2
530+ let $t01521815272 = chainMeta(chainId)
531+ let chainHeight = $t01521815272._1
532+ let chainLastBlock = $t01521815272._2
515533 let checkReference = isReferenceCorrect(referenceHex, chainLastBlock)
516534 if ((checkReference == checkReference))
517535 then {
518536 let newChainHeight = (chainHeight + 1)
519- let mainChainEntry = if ((supportingBalance(chainId) > (computedTotalBalance / 2)))
520- then [IntegerEntry(mainChainIdKey, chainId), IntegerEntry(firstValidAltChainIdKey, (valueOrElse(getInteger(lastChainIdKey), 0) + 1))]
537+ let prevEpoch = blockMeta(referenceHex)._2
538+ let updateMainChainData = if ((supportingBalance(chainId) > (computedTotalBalance / 2)))
539+ then {
540+ let updateFinalizedBlock = getUpdateFinalizedBlockAction(i.originCaller, blockHashHex, prevEpoch)
541+ ([IntegerEntry(mainChainIdKey, chainId), IntegerEntry(firstValidAltChainIdKey, (valueOrElse(getInteger(lastChainIdKey), 0) + 1))] ++ updateFinalizedBlock)
542+ }
521543 else nil
522544 let thisEpochMeta = match epochMeta(height) {
523545 case _: Unit =>
524- StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(blockMeta(referenceHex)._2)) + SEP) + blockHashHex))
546+ StringEntry(epochMetaKey(height), ((((toString(i.originCaller) + SEP) + toString(prevEpoch)) + SEP) + blockHashHex))
525547 case other =>
526548 throw("Epoch already started")
527549 }
528- let updateMainChainLastMinedBlock = if (if ((mainChainEntry == nil))
550+ let updateMainChainLastMinedBlock = if (if ((updateMainChainData == nil))
529551 then (valueOrElse(minerChainId(i.originCaller), 0) != chainId)
530552 else false)
531553 then [IntegerEntry(chainLastHeightKey(mainChainId, i.originCaller), blockMeta(getStringValue(chainFirstBlockIdKey(chainId)))._1)]
532554 else nil
533555 let newBlockMeta = (((toBytes(newChainHeight) + toBytes(height)) + fromBase16String(referenceHex)) + i.originCaller.bytes)
534- ((([BinaryEntry((blockMetaK + blockHashHex), newBlockMeta), StringEntry(chainMetaKey(chainId), ((toString(newChainHeight) + SEP) + blockHashHex)), thisEpochMeta, IntegerEntry(minerChainIdKey(i.originCaller), chainId), IntegerEntry(chainLastHeightKey(chainId, i.originCaller), newChainHeight)] ++ mainChainEntry) ++ addSupporter(chainId, i.originCaller)) ++ updateMainChainLastMinedBlock)
556+ ((([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)
535557 }
536558 else throw("Strict value is not equal to itself.")
537559 }
538560 else throw("Strict value is not equal to itself.")
539561 }
540562 else throw("Strict value is not equal to itself.")
541563 }
542564 else throw("Strict value is not equal to itself.")
543565 }
544566
545567
546568
547569 @Callable(i)
548570 func join (rewardAddress) = {
549571 func checkRewardAddress (address) = match getBinary(minerPkKey(address)) {
550572 case pk: ByteVector =>
551573 if ((pk == i.originCallerPublicKey))
552574 then unit
553575 else throw(((("L2 miner address " + address) + " is already linked with ") + toBase58String(pk)))
554576 case _ =>
555577 unit
556578 }
557579
558580 if (!(isContractSetup()))
559581 then throw("The contract has not yet set up")
560582 else if ((MIN_BALANCE > wavesBalance(i.originCaller).generating))
561583 then throw(((("Insufficient generating balance: " + toString(wavesBalance(i.originCaller).generating)) + ". Required: ") + toString(MIN_BALANCE)))
562584 else if ((size(rewardAddress) != 20))
563585 then throw("rewardAddress should be an L2 address")
564586 else if ((size(allMiners) >= 50))
565587 then throw("too many miners")
566588 else {
567589 func checkExistence (exists,miner) = if (exists)
568590 then true
569591 else (miner == toString(i.originCaller))
570592
571593 let alreadyExists = {
572594 let $l = allMiners
573595 let $s = size($l)
574596 let $acc0 = false
575597 func $f0_1 ($a,$i) = if (($i >= $s))
576598 then $a
577599 else checkExistence($a, $l[$i])
578600
579601 func $f0_2 ($a,$i) = if (($i >= $s))
580602 then $a
581603 else throw("List size exceeds 50")
582604
583605 $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)
584606 }
585607 if (alreadyExists)
586608 then nil
587609 else {
588610 let newMiner = toString(i.originCaller)
589611 let rewardAddressHex = toBase16String(rewardAddress)
590612 let check = checkRewardAddress(rewardAddressHex)
591613 if ((check == check))
592614 then {
593615 let newMiners = if ((size(allMiners) == 0))
594616 then newMiner
595617 else ((allMinersStr + SEP) + newMiner)
596618 let deleteOldRewardAddressPk = match getString(minerRewardAddressKey(newMiner)) {
597619 case oldAddress: String =>
598620 if ((oldAddress == toBase16String(rewardAddress)))
599621 then nil
600622 else [DeleteEntry(minerPkKey(oldAddress))]
601623 case _ =>
602624 nil
603625 }
604626 ([StringEntry(allMinersKey, newMiners), StringEntry(minerRewardAddressKey(newMiner), ("0x" + rewardAddressHex)), BinaryEntry(minerPkKey(rewardAddressHex), i.originCallerPublicKey)] ++ deleteOldRewardAddressPk)
605627 }
606628 else throw("Strict value is not equal to itself.")
607629 }
608630 }
609631 }
610632
611633
612634
613635 @Callable(i)
614636 func leave () = {
615637 let leavingMiner = toString(i.originCaller)
616638 func skipLeavingMiner (acc,miner) = if ((miner == leavingMiner))
617639 then acc
618640 else (acc :+ miner)
619641
620642 let remainingMiners = {
621643 let $l = allMiners
622644 let $s = size($l)
623645 let $acc0 = nil
624646 func $f0_1 ($a,$i) = if (($i >= $s))
625647 then $a
626648 else skipLeavingMiner($a, $l[$i])
627649
628650 func $f0_2 ($a,$i) = if (($i >= $s))
629651 then $a
630652 else throw("List size exceeds 50")
631653
632654 $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)
633655 }
634656 let rewardAddrKey = minerRewardAddressKey(leavingMiner)
635657 let prevRewardAddress = valueOrErrorMessage(getString(this, rewardAddrKey), "miner has never joined")
636658 if ((thisEpochMiner == i.originCaller))
637659 then throw("designated miner can't leave")
638660 else [StringEntry(allMinersKey, makeString_2C(remainingMiners, SEP)), DeleteEntry(rewardAddrKey), DeleteEntry(minerPkKey(prevRewardAddress))]
639661 }
640662
641663
642664
643665 @Callable(i)
644666 func setup (genesisBlockHashHex,minerReward,stakingContractAddressB58) = if (isContractSetup())
645667 then throw("The contract has been already set up")
646668 else {
647669 let genesisBlockHash = fromBase16String(genesisBlockHashHex)
648670 let emptyPk = base58'11111111111111111111111111111111'
649671 let genesisMinerAddress = addressFromPublicKey(emptyPk)
650672 let genesisEthRewardAddress = base58'11111111111111111111'
651673 let genesisBlockReferenceHash = base58'11111111111111111111111111111111'
652674 let genesisBlockMeta = (((toBytes(0) + toBytes(height)) + genesisBlockReferenceHash) + genesisMinerAddress.bytes)
653-[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))]
675+[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)]
654676 }
655677
656678

github/deemru/w8io/873ac7e 
97.09 ms