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