tx · EuXdBSC64ERnDjXwNWTLZ8E4i7NvL3ZhBhtv2he8MwkJ 3MsqKJ6o1ABE37676cHHBxJRs6huYTt72ch: -0.02300000 Waves 2024.04.03 17:55 [3046754] smart account 3MsqKJ6o1ABE37676cHHBxJRs6huYTt72ch > SELF 0.00000000 Waves
{ "type": 13, "id": "EuXdBSC64ERnDjXwNWTLZ8E4i7NvL3ZhBhtv2he8MwkJ", "fee": 2300000, "feeAssetId": null, "timestamp": 1712159695000, "version": 1, "sender": "3MsqKJ6o1ABE37676cHHBxJRs6huYTt72ch", "senderPublicKey": "3xjN6fjYDXBGUE1mcRw2Fvr4R6tEZnuJA98QFGF99sXd", "proofs": [ "3fDFa24maL6s818qSCgMujs9AWEvFvkZurscVpnUMtnnNWAegCsrtpMtaPbd3apBRvX7sXcU9GW6eDeqMrwVkiu6" ], "script": "base64:CAIlCAISBAoCAgISBQoDAgIBEgUKAwICARIGCgQBAgIBEgMKAQISADIAB0lOVF9NQVgA//////////9/AAVXQVZFUwCAwtcvAAtNSU5fQkFMQU5DRQkAaAIAoJwBBQVXQVZFUwATTUFYX0JMT0NLU19BVF9FUE9DSAAyAANTRVACASwAD0JMT0NLX0hBU0hfU0laRQAgAAxBRERSRVNTX1NJWkUAGgATTUFYX0JMT0NLU19TVFJfU0laRQkAZAIJAGgCAEAFE01BWF9CTE9DS1NfQVRfRVBPQ0gJAGUCBRNNQVhfQkxPQ0tTX0FUX0VQT0NIAAEAEHRoaXNFcG9jaERhdGFLZXkCDXRoaXNFcG9jaERhdGEADGFsbE1pbmVyc0tleQIJYWxsTWluZXJzAA5tYWluQ2hhaW5JZEtleQILbWFpbkNoYWluSWQADmxhc3RDaGFpbklkS2V5AgtsYXN0Q2hhaW5JZAAYbGFzdEVwb2NoQmxvY2tzTnVtYmVyS2V5AhVsYXN0RXBvY2hCbG9ja3NOdW1iZXIADm1pbmVyUmV3YXJkS2V5AgttaW5lclJld2FyZAAWc3Rha2luZ0NvbnRyYWN0QWRkcmVzcwkBB0FkZHJlc3MBCQERQGV4dHJOYXRpdmUoMTA1MikCBQR0aGlzAhZzdGFraW5nQ29udHJhY3RBZGRyZXNzARFnZW5lcmF0aW5nQmFsYW5jZQEHYWRkcmVzcwQHJG1hdGNoMAkAnQgCBRZzdGFraW5nQ29udHJhY3RBZGRyZXNzCQCsAgICBCVzX18JAKUIAQUHYWRkcmVzcwMJAAECBQckbWF0Y2gwAgZTdHJpbmcEA3N0cgUHJG1hdGNoMAQJcGFyYW1MaXN0CQC1CQIFA3N0cgICX18ECnByZXZIZWlnaHQJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQlwYXJhbUxpc3QAAQQLcHJldkJhbGFuY2UJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQlwYXJhbUxpc3QAAgQKbmV4dEhlaWdodAkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCXBhcmFtTGlzdAADBAtuZXh0QmFsYW5jZQkBDXBhcnNlSW50VmFsdWUBCQCRAwIFCXBhcmFtTGlzdAAEAwkAZwIFBmhlaWdodAUKbmV4dEhlaWdodAULbmV4dEJhbGFuY2UDCQBnAgUGaGVpZ2h0BQpwcmV2SGVpZ2h0BQtwcmV2QmFsYW5jZQAAAAABDGJsb2NrTWV0YUtleQEHYmxvY2tJZAkArAICAglibG9ja01ldGEJANwEAQUHYmxvY2tJZAEKY2hhaW5JZEtleQEJZ2VuZXJhdG9yCQCsAgICCWNoYWluSWRPZgkA3AQBBQlnZW5lcmF0b3IBDmNoYWluSGVpZ2h0S2V5AQdjaGFpbklkCQCsAgIJAKwCAgIFY2hhaW4JAKQDAQUHY2hhaW5JZAIGSGVpZ2h0ARRjaGFpbkZpcnN0QmxvY2tJZEtleQEHY2hhaW5JZAkArAICCQCsAgICBWNoYWluCQCkAwEFB2NoYWluSWQCCkZpcnN0QmxvY2sBE2NoYWluTGFzdEJsb2NrSWRLZXkBB2NoYWluSWQJAKwCAgkArAICAgVjaGFpbgkApAMBBQdjaGFpbklkAglMYXN0QmxvY2sBE2NoYWluQWxsQmxvY2tJZHNLZXkCB2NoYWluSWQBbgkArAICCQCsAgIJAKwCAgIFY2hhaW4JAKQDAQUHY2hhaW5JZAIJQWxsQmxvY2tzCQCkAwEFAW4BGGNoYWluQWxsQmxvY2tJZHNMYXN0TktleQEHY2hhaW5JZAkArAICCQCsAgICBWNoYWluCQCkAwEFB2NoYWluSWQCDkFsbEJsb2Nrc0xhc3ROAQ1zdXBwb3J0ZXJzS2V5AQdjaGFpbklkCQCsAgIJAKwCAgIFY2hhaW4JAKQDAQUHY2hhaW5JZAIKU3VwcG9ydGVycwESbWluZXJSZXdhcmRBZGRyZXNzAQltaW5lckFkZHIJAKwCAgkArAICAgVtaW5lcgUJbWluZXJBZGRyAg1SZXdhcmRBZGRyZXNzARJtaW5lckpvaW5IZWlnaHRLZXkBCW1pbmVyQWRkcgkArAICCQCsAgICBW1pbmVyBQltaW5lckFkZHICCkpvaW5IZWlnaHQBCm1pbmVyUGtLZXkBDXJld2FyZEFkZHJlc3MJAKwCAgkArAICAgVtaW5lcgUNcmV3YXJkQWRkcmVzcwICUEsBEGxlYXZpbmdNaW5lcnNLZXkBBWVwb2NoCQCsAgICD2xlYXZpbmdNaW5lcnNBdAkApAMBBQVlcG9jaAALbWFpbkNoYWluSWQJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUObWFpbkNoYWluSWRLZXkAAAAOdGhpc0Vwb2NoTWluZXIEByRtYXRjaDAJAKIIAQUQdGhpc0Vwb2NoRGF0YUtleQMJAAECBQckbWF0Y2gwAgZTdHJpbmcEEHJhd1RoaXNFcG9jaERhdGEFByRtYXRjaDAEDXRoaXNFcG9jaERhdGEJALUJAgUQcmF3VGhpc0Vwb2NoRGF0YQUDU0VQBAl0aGlzRXBvY2gJAQ1wYXJzZUludFZhbHVlAQkAkQMCBQ10aGlzRXBvY2hEYXRhAAADCQAAAgUJdGhpc0Vwb2NoBQZoZWlnaHQJANkEAQkAkQMCBQ10aGlzRXBvY2hEYXRhAAEFBHVuaXQFBHVuaXQACWFsbE1pbmVycwQHJG1hdGNoMAkAoggBBQxhbGxNaW5lcnNLZXkDCQABAgUHJG1hdGNoMAIGU3RyaW5nBANyYXcFByRtYXRjaDAJALwJAgUDcmF3BQNTRVAFA25pbAAQYWxsTGVhdmluZ01pbmVycwQHJG1hdGNoMAkAoggBCQEQbGVhdmluZ01pbmVyc0tleQEFBmhlaWdodAMJAAECBQckbWF0Y2gwAgZTdHJpbmcEA3JhdwUHJG1hdGNoMAkAvAkCBQNyYXcFA1NFUAUDbmlsAQlibG9ja01ldGEBB2Jsb2NrSWQEBG1ldGEJARFAZXh0ck5hdGl2ZSgxMDU3KQEJAQxibG9ja01ldGFLZXkBBQdibG9ja0lkBBFtZXRhV2l0aG91dEhlaWdodAkAygECBQRtZXRhAAgEFm1ldGFXaXRob3V0SGVpZ2h0RXBvY2gJAMoBAgURbWV0YVdpdGhvdXRIZWlnaHQACAQLYmxvY2tIZWlnaHQJALEJAQkAyQECBQRtZXRhAAgECmJsb2NrRXBvY2gJALEJAQkAyQECBRFtZXRhV2l0aG91dEhlaWdodAAIBAtibG9ja1BhcmVudAkAyQECBRZtZXRhV2l0aG91dEhlaWdodEVwb2NoBQ9CTE9DS19IQVNIX1NJWkUEDmJsb2NrR2VuZXJhdG9yCQDMAQIFBG1ldGEFDEFERFJFU1NfU0laRQkAlgoEBQtibG9ja0hlaWdodAUKYmxvY2tFcG9jaAULYmxvY2tQYXJlbnQFDmJsb2NrR2VuZXJhdG9yAQxzZXRFcG9jaERhdGEBCWdlbmVyYXRvcgkBC1N0cmluZ0VudHJ5AgUQdGhpc0Vwb2NoRGF0YUtleQkArAICCQCsAgIJAKQDAQUGaGVpZ2h0BQNTRVAJANgEAQgFCWdlbmVyYXRvcgVieXRlcwALJHQwMzY1MzQ3MTAECWhpdFNvdXJjZQQHJG1hdGNoMAgFCWxhc3RCbG9jawN2cmYDCQABAgUHJG1hdGNoMAIKQnl0ZVZlY3RvcgQDdnJmBQckbWF0Y2gwBQN2cmYIBQlsYXN0QmxvY2sTZ2VuZXJhdGlvblNpZ25hdHVyZQoBDHByb2Nlc3NNaW5lcgIEcHJldgVtaW5lcgQLJHQwMzk1MTQwMTQFBHByZXYECXByZXZEZWxheQgFCyR0MDM5NTE0MDE0Al8xBAlwcmV2TWluZXIIBQskdDAzOTUxNDAxNAJfMgQQcHJldlRvdGFsQmFsYW5jZQgFCyR0MDM5NTE0MDE0Al8zBApwcmV2TWluZXJzCAULJHQwMzk1MTQwMTQCXzQEDG1pbmVyQWRkcmVzcwkBEUBleHRyTmF0aXZlKDEwNjIpAQUFbWluZXIED3dhdmVzR2VuQmFsYW5jZQgJAO8HAQUMbWluZXJBZGRyZXNzCmdlbmVyYXRpbmcEDG1pbmVyQmFsYW5jZQkBEWdlbmVyYXRpbmdCYWxhbmNlAQUMbWluZXJBZGRyZXNzAwMDCQBmAgULTUlOX0JBTEFOQ0UFD3dhdmVzR2VuQmFsYW5jZQYJAGcCAAAFDG1pbmVyQmFsYW5jZQYJAGYCCQELdmFsdWVPckVsc2UCCQCfCAEJARJtaW5lckpvaW5IZWlnaHRLZXkBBQVtaW5lcgUHSU5UX01BWAUGaGVpZ2h0BQRwcmV2BAluZXh0RGVsYXkJAIUHAgUMbWluZXJBZGRyZXNzBQxtaW5lckJhbGFuY2UDCQBmAgUJcHJldkRlbGF5BQluZXh0RGVsYXkJAJYKBAUJbmV4dERlbGF5BQVtaW5lcgkAZAIFEHByZXZUb3RhbEJhbGFuY2UFDG1pbmVyQmFsYW5jZQkAzQgCBQpwcmV2TWluZXJzBQVtaW5lcgkAlgoEBQlwcmV2RGVsYXkFCXByZXZNaW5lcgkAZAIFEHByZXZUb3RhbEJhbGFuY2UFDG1pbmVyQmFsYW5jZQkAzQgCBQpwcmV2TWluZXJzBQVtaW5lcgoAAiRsCQDOCAIFCWFsbE1pbmVycwUQYWxsTGVhdmluZ01pbmVycwoAAiRzCQCQAwEFAiRsCgAFJGFjYzAJAJYKBAUHSU5UX01BWAIAAAAFA25pbAoBBSRmMF8xAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQEMcHJvY2Vzc01pbmVyAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhRMaXN0IHNpemUgZXhjZWVkcyA1MAkBBSRmMF8yAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgkBBSRmMF8xAgUFJGFjYzAAAAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIADWNvbXB1dGVkRGVsYXkIBQskdDAzNjUzNDcxMAJfMQARY29tcHV0ZWRHZW5lcmF0b3IIBQskdDAzNjUzNDcxMAJfMgAUY29tcHV0ZWRUb3RhbEJhbGFuY2UIBQskdDAzNjUzNDcxMAJfMwAOZmlsdGVyZWRNaW5lcnMIBQskdDAzNjUzNDcxMAJfNAASc2FmZVJvbGxiYWNrSGVpZ2h0CgEKYWRkQmFsYW5jZQIDYWNjCmJsb2NrSWRTdHIECyR0MDQ4MjQ0ODY4BQNhY2MEDHRvdGFsQmFsYW5jZQgFCyR0MDQ4MjQ0ODY4Al8xBAZwcmV2SWQIBQskdDA0ODI0NDg2OAJfMgQKZ2VuZXJhdG9ycwgFCyR0MDQ4MjQ0ODY4Al8zAwkAZgIFDHRvdGFsQmFsYW5jZQkAaQIFFGNvbXB1dGVkVG90YWxCYWxhbmNlAAIFA2FjYwQHYmxvY2tJZAkA3QQBBQpibG9ja0lkU3RyBAlnZW5lcmF0b3IJAQdBZGRyZXNzAQgJAQlibG9ja01ldGEBBQdibG9ja0lkAl80AwkBD2NvbnRhaW5zRWxlbWVudAIFCmdlbmVyYXRvcnMFCWdlbmVyYXRvcgUDYWNjBAdiYWxhbmNlCQERZ2VuZXJhdGluZ0JhbGFuY2UBBQlnZW5lcmF0b3IJAJUKAwkAZAIFDHRvdGFsQmFsYW5jZQUHYmFsYW5jZQUHYmxvY2tJZAkAzQgCBQpnZW5lcmF0b3JzBQlnZW5lcmF0b3IKAQtnZXRCbG9ja0lkcwEBbgQGcmF3U3RyCQELdmFsdWVPckVsc2UCCQCiCAEJARNjaGFpbkFsbEJsb2NrSWRzS2V5AgULbWFpbkNoYWluSWQFAW4CAAMJAAACBQZyYXdTdHICAAUDbmlsCQC8CQIFBnJhd1N0cgUDU0VQBAVsYXN0TgkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEYY2hhaW5BbGxCbG9ja0lkc0xhc3ROS2V5AQULbWFpbkNoYWluSWQAAAQMYWxsQmxvY2tzSWRzCQDOCAIJAM4IAgkAzggCCQELZ2V0QmxvY2tJZHMBBQVsYXN0TgkBC2dldEJsb2NrSWRzAQkAZQIFBWxhc3ROAAEJAQtnZXRCbG9ja0lkcwEJAGUCBQVsYXN0TgACCQELZ2V0QmxvY2tJZHMBCQBlAgUFbGFzdE4AAwQLJHQwNTYzNjU3MTAKAAIkbAUMYWxsQmxvY2tzSWRzCgACJHMJAJADAQUCJGwKAAUkYWNjMAkAlQoDAAABAAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQphZGRCYWxhbmNlAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhVMaXN0IHNpemUgZXhjZWVkcyAyMDAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBf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ZWN0b3IEAmxiBQckbWF0Y2gwAwkAAAIFCXJlZmVyZW5jZQUCbGIFBHVuaXQJAAIBCQCsAgIJAKwCAgkArAICAi5FeHBlY3RlZCBhIHJlZmVyZW5jZSB0byB0aGUgY2hhaW4gbGFzdCBibG9jazogCQDcBAEFAmxiAgcuIEdvdDogCQDcBAEFCXJlZmVyZW5jZQkAAgECC01hdGNoIGVycm9yAQ9jaGFpbklzSW5hY3RpdmUBB2NoYWluSWQEDGZpcnN0QmxvY2tJZAkBEUBleHRyTmF0aXZlKDEwNTcpAQkBFGNoYWluRmlyc3RCbG9ja0lkS2V5AQUHY2hhaW5JZAkAZgIFEnNhZmVSb2xsYmFja0hlaWdodAgJAQlibG9ja01ldGEBBQxmaXJzdEJsb2NrSWQCXzEBGWVuc3VyZU1haW5PckluYWN0aXZlQ2hhaW4BCWdlbmVyYXRvcgQHJG1hdGNoMAkAnwgBCQEKY2hhaW5JZEtleQEIBQlnZW5lcmF0b3IFYnl0ZXMDCQABAgUHJG1hdGNoMAIDSW50BAljdXJyZW50SWQFByRtYXRjaDADAwkAAAIFCWN1cnJlbnRJZAULbWFpbkNoYWluSWQGCQEPY2hhaW5Jc0luYWN0aXZlAQUJY3VycmVudElkBQR1bml0CQACAQkArAICAhxtaW5lciBpcyBtaW5pbmcgb3RoZXIgY2hhaW4gCQCkAwEFCWN1cnJlbnRJZAUEdW5pdAEXZW5zdXJlQWx0Q2hhaW5FeHRlbnNpb24CCWdlbmVyYXRvcgdjaGFpbklkBAckbWF0Y2gwCQCfCAEJAQpjaGFpbklkS2V5AQgFCWdlbmVyYXRvcgVieXRlcwMJAAECBQckbWF0Y2gwAgNJbnQECWN1cnJlbnRJZAUHJG1hdGNoMAMJAAACBQljdXJyZW50SWQFB2NoYWluSWQFBHVuaXQEFWV4dGVuZGluZ0ZpcnN0QmxvY2tJZAkBEUBleHRyTmF0aXZlKDEwNTcpAQkBFGNoYWluRmlyc3RCbG9ja0lkS2V5AQUHY2hhaW5JZAQYbWluZXJDdXJyZW50Rmlyc3RCbG9ja0lkCQERQGV4dHJOYXRpdmUoMTA1NykBCQEUY2hhaW5GaXJzdEJsb2NrSWRLZXkBBQljdXJyZW50SWQEGWV4dGVuZGluZ0ZpcnN0QmxvY2tIZWlnaHQICQEJYmxvY2tNZXRhAQUVZXh0ZW5kaW5nRmlyc3RCbG9ja0lkAl8xBBxtaW5lckN1cnJlbnRGaXJzdEJsb2NrSGVpZ2h0CAkBCWJsb2NrTWV0YQEFGG1pbmVyQ3VycmVudEZpcnN0QmxvY2tJZAJfMQMJAGYCBRlleHRlbmRpbmdGaXJzdEJsb2NrSGVpZ2h0BRxtaW5lckN1cnJlbnRGaXJzdEJsb2NrSGVpZ2h0BQR1bml0CQACAQkArAICCQCsAgIJAKwCAgkArAICCQCsAgICHG1pbmVyIGlzIG1pbmluZyBvdGhlciBjaGFpbiAJAKQDAQUJY3VycmVudElkAiYsIGhlaWdodCBvZiB0aGUgYWx0IGNoYWluIGZpcnN0IGJsb2NrIAkApAMBBRlleHRlbmRpbmdGaXJzdEJsb2NrSGVpZ2h0Aj8gaXMgbm90IGxlc3MgdGhhbiBoZWlnaHQgb2YgdGhlIG1pbmVyIGFjdGl2ZSBjaGFpbiBmaXJzdCBibG9jayAJAKQDAQUcbWluZXJDdXJyZW50Rmlyc3RCbG9ja0hlaWdodAUEdW5pdAEgZW5zdXJlUmVmZXJlbmNlSXNTYWZlRm9yUm9sbGJhY2sBCXJlZmVyZW5jZQQLc3RhcnRIZWlnaHQICQEJYmxvY2tNZXRhAQUJcmVmZXJlbmNlAl8xAwkAZgIFEnNhZmVSb2xsYmFja0hlaWdodAULc3RhcnRIZWlnaHQJAAIBCQCsAgIJAKwCAgkArAICAg1zdGFydCBoZWlnaHQgCQCkAwEFC3N0YXJ0SGVpZ2h0Ah0gaXMgbGVzcyB0aGFuIG1pbmltdW0gaGVpZ2h0IAkApAMBBRJzYWZlUm9sbGJhY2tIZWlnaHQFBHVuaXQBEmVuc3VyZUNvcnJlY3RFcG9jaAEFZXBvY2gDCQAAAgUFZXBvY2gFBmhlaWdodAUEdW5pdAkAAgEJAKwCAgkArAICCQCsAgICGkV4cGVjdGVkIGJsb2NrIGZyb20gZXBvY2ggCQCkAwEFBmhlaWdodAIGLiBHb3QgCQCkAwEFBWVwb2NoARFjaGVja0Jsb2Nrc051bWJlcgADCQBmAgUTTUFYX0JMT0NLU19BVF9FUE9DSAkBEUBleHRyTmF0aXZlKDEwNTUpAQUYbGFzdEVwb2NoQmxvY2tzTnVtYmVyS2V5BQR1bml0CQACAQIiTWF4IGJsb2NrcyBudW1iZXIgYXQgZXBvY2ggcmVhY2hlZAEMYWRkU3VwcG9ydGVyAgdjaGFpbklkCWdlbmVyYXRvcgQNc3VwcG9ydGVyc1N0cgkBEUBleHRyTmF0aXZlKDEwNTgpAQkBDXN1cHBvcnRlcnNLZXkBBQdjaGFpbklkBApzdXBwb3J0ZXJzCQC1CQIFDXN1cHBvcnRlcnNTdHIFA1NFUAMJAQ9jb250YWluc0VsZW1lbnQCBQpzdXBwb3J0ZXJzCQClCAEFCWdlbmVyYXRvcgUDbmlsCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQ1zdXBwb3J0ZXJzS2V5AQUHY2hhaW5JZAkArAICCQCsAgIFDXN1cHBvcnRlcnNTdHIFA1NFUAkApQgBBQlnZW5lcmF0b3IFA25pbAYBaQELYXBwZW5kQmxvY2sCCWJsb2NrSGFzaAlyZWZlcmVuY2UEBWNoZWNrCQERY2hlY2tCbG9ja3NOdW1iZXIAAwkAAAIFBWNoZWNrBQVjaGVjawMJAQIhPQIFDnRoaXNFcG9jaE1pbmVyCAgFAWkMb3JpZ2luQ2FsbGVyBWJ5dGVzBAckbWF0Y2gwBQ50aGlzRXBvY2hNaW5lcgMJAAECBQckbWF0Y2gwAgpCeXRlVmVjdG9yBAplcG9jaE1pbmVyBQckbWF0Y2gwCQACAQkArAICAjlub3QgYWxsb3dlZCB0byBmb3JnZSBibG9ja3MgaW4gdGhpcyBlcG9jaCwgZXhwZWN0ZWQgZnJvbSAJANgEAQUKZXBvY2hNaW5lcgkAAgECQG5vdCBhbGxvd2VkIHRvIGZvcmdlIGJsb2NrcyBpbiB0aGlzIGVwb2NoLCBlcG9jaCBtaW5lciBpcyBhYnNlbnQEB2NoYWluSWQJAQt2YWx1ZU9yRWxzZQIJAJ8IAQkBCmNoYWluSWRLZXkBCAgFAWkMb3JpZ2luQ2FsbGVyBWJ5dGVzBQttYWluQ2hhaW5JZAQLbGFzdEJsb2NrSWQJARFAZXh0ck5hdGl2ZSgxMDU3KQEJARNjaGFpbkxhc3RCbG9ja0lkS2V5AQUHY2hhaW5JZAQGY2hlY2syCQESaXNSZWZlcmVuY2VDb3JyZWN0AgUJcmVmZXJlbmNlBQtsYXN0QmxvY2tJZAMJAAACBQZjaGVjazIFBmNoZWNrMgQLY2hhaW5IZWlnaHQJAQt2YWx1ZU9yRWxzZQIJAJ8IAQkBDmNoYWluSGVpZ2h0S2V5AQUHY2hhaW5JZAAABAluZXdIZWlnaHQJAGQCBQtjaGFpbkhlaWdodAABBAxibG9ja3NOdW1iZXIJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUYbGFzdEVwb2NoQmxvY2tzTnVtYmVyS2V5AAAEDG5ld0Jsb2NrTWV0YQkAywECCQDLAQIJAMsBAgkAmgMBBQluZXdIZWlnaHQJAJoDAQUGaGVpZ2h0BQtsYXN0QmxvY2tJZAgIBQFpDG9yaWdpbkNhbGxlcgVieXRlcwkAzAgCCQELQmluYXJ5RW50cnkCCQEMYmxvY2tNZXRhS2V5AQUJYmxvY2tIYXNoBQxuZXdCbG9ja01ldGEJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ5jaGFpbkhlaWdodEtleQEFB2NoYWluSWQFCW5ld0hlaWdodAkAzAgCCQELQmluYXJ5RW50cnkCCQETY2hhaW5MYXN0QmxvY2tJZEtleQEFB2NoYWluSWQFCWJsb2NrSGFzaAkAzAgCCQEMSW50ZWdlckVudHJ5AgUYbGFzdEVwb2NoQmxvY2tzTnVtYmVyS2V5CQBkAgUMYmxvY2tzTnVtYmVyAAEFA25pbAkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgkAAgECJFN0cmljdCB2YWx1ZSBpcyBub3QgZXF1YWwgdG8gaXRzZWxmLgFpAQ9leHRlbmRNYWluQ2hhaW4DCWJsb2NrSGFzaAlyZWZlcmVuY2UFZXBvY2gECmNoZWNrRXBvY2gJARJlbnN1cmVDb3JyZWN0RXBvY2gBBQVlcG9jaAMJAAACBQpjaGVja0Vwb2NoBQpjaGVja0Vwb2NoBA5jaGVja0dlbmVyYXRvcgkBEWVuc3VyZU1pbmluZ0Vwb2NoAQgFAWkMb3JpZ2luQ2FsbGVyAwkAAAIFDmNoZWNrR2VuZXJhdG9yBQ5jaGVja0dlbmVyYXRvcgQKY2hlY2tDaGFpbgkBGWVuc3VyZU1haW5PckluYWN0aXZlQ2hhaW4BCAUBaQxvcmlnaW5DYWxsZXIDCQAAAgUKY2hlY2tDaGFpbgUKY2hlY2tDaGFpbgQLY2hhaW5IZWlnaHQJAQt2YWx1ZU9yRWxzZQIJAJ8IAQkBDmNoYWluSGVpZ2h0S2V5AQULbWFpbkNoYWluSWQAAAQQbGFzdFZhbGlkQmxvY2tJZAkAoQgBCQETY2hhaW5MYXN0QmxvY2tJZEtleQEFC21haW5DaGFpbklkBA5jaGVja1JlZmVyZW5jZQkBEmlzUmVmZXJlbmNlQ29ycmVjdAIFCXJlZmVyZW5jZQUQbGFzdFZhbGlkQmxvY2tJZAMJAAACBQ5jaGVja1JlZmVyZW5jZQUOY2hlY2tSZWZlcmVuY2UEDWJsb2NrSWRzTGFzdE4JAQt2YWx1ZU9yRWxzZQIJAJ8IAQkBGGNoYWluQWxsQmxvY2tJZHNMYXN0TktleQEFC21haW5DaGFpbklkAAAECGJsb2NrSWRzCQELdmFsdWVPckVsc2UCCQCiCAEJARNjaGFpbkFsbEJsb2NrSWRzS2V5AgULbWFpbkNoYWluSWQFDWJsb2NrSWRzTGFzdE4CAAQJbmV3SGVpZ2h0CQBkAgULY2hhaW5IZWlnaHQAAQQRdXBkYXRlQWxsQmxvY2tJZHMDCQBnAgkAsQIBBQhibG9ja0lkcwUTTUFYX0JMT0NLU19TVFJfU0laRQkAzAgCCQEMSW50ZWdlckVudHJ5AgkBGGNoYWluQWxsQmxvY2tJZHNMYXN0TktleQEFC21haW5DaGFpbklkCQBkAgUNYmxvY2tJZHNMYXN0TgABCQDMCAIJAQtTdHJpbmdFbnRyeQIJARNjaGFpbkFsbEJsb2NrSWRzS2V5AgULbWFpbkNoYWluSWQJAGQCBQ1ibG9ja0lkc0xhc3ROAAEJANwEAQUJYmxvY2tIYXNoBQNuaWwEC25ld0Jsb2NrSWRzAwkAAAIFCGJsb2NrSWRzAgAJANwEAQUJYmxvY2tIYXNoCQCsAgIJAKwCAgkA3AQBBQlibG9ja0hhc2gFA1NFUAUIYmxvY2tJZHMJAMwIAgkBC1N0cmluZ0VudHJ5AgkBE2NoYWluQWxsQmxvY2tJZHNLZXkCBQttYWluQ2hhaW5JZAUNYmxvY2tJZHNMYXN0TgULbmV3QmxvY2tJZHMFA25pbAQMZmlyc3RCbG9ja0lkBAckbWF0Y2gwBRBsYXN0VmFsaWRCbG9ja0lkAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAmlkBQckbWF0Y2gwBQNuaWwJAMwIAgkBC0JpbmFyeUVudHJ5AgkBFGNoYWluRmlyc3RCbG9ja0lkS2V5AQULbWFpbkNoYWluSWQFCWJsb2NrSGFzaAUDbmlsBAxuZXdCbG9ja01ldGEJAMsBAgkAywECCQDLAQIJAJoDAQUJbmV3SGVpZ2h0CQCaAwEFBmhlaWdodAUJcmVmZXJlbmNlCAgFAWkMb3JpZ2luQ2FsbGVyBWJ5dGVzCQDOCAIJAM4IAgkAzAgCCQELQmluYXJ5RW50cnkCCQEMYmxvY2tNZXRhS2V5AQUJYmxvY2tIYXNoBQxuZXdCbG9ja01ldGEJAMwIAgkBDEludGVnZXJFbnRyeQIJAQ5jaGFpbkhlaWdodEtleQEFC21haW5DaGFpbklkBQluZXdIZWlnaHQJAMwIAgkBC0JpbmFyeUVudHJ5AgkBE2NoYWluTGFzdEJsb2NrSWRLZXkBBQttYWluQ2hhaW5JZAUJYmxvY2tIYXNoCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEKY2hhaW5JZEtleQEICAUBaQxvcmlnaW5DYWxsZXIFYnl0ZXMFC21haW5DaGFpbklkCQDMCAIJAQxzZXRFcG9jaERhdGEBCAUBaQxvcmlnaW5DYWxsZXIJAMwIAgkBDEludGVnZXJFbnRyeQIFGGxhc3RFcG9jaEJsb2Nrc051bWJlcktleQABBQNuaWwFDGZpcnN0QmxvY2tJZAURdXBkYXRlQWxsQmxvY2tJZHMJAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4JAAIBAiRTdHJpY3QgdmFsdWUgaXMgbm90IGVxdWFsIHRvIGl0c2VsZi4BaQENc3RhcnRBbHRDaGFpbgMJYmxvY2tIYXNoCXJlZmVyZW5jZQVlcG9jaAQKY2hlY2tFcG9jaAkBEmVuc3VyZUNvcnJlY3RFcG9jaAEFBWVwb2NoAwkAAAIFCmNoZWNrRXBvY2gFCmNoZWNrRXBvY2gEDmNoZWNrUmVmZXJlbmNlCQEgZW5zdXJlUmVmZXJlbmNlSXNTYWZlRm9yUm9sbGJhY2sBBQlyZWZlcmVuY2UDCQAAAgUOY2hlY2tSZWZlcmVuY2UFDmNoZWNrUmVmZXJlbmNlBA5jaGVja0dlbmVyYXRvcgkBEWVuc3VyZU1pbmluZ0Vwb2NoAQgFAWkMb3JpZ2luQ2FsbGVyAwkAAAIFDmNoZWNrR2VuZXJhdG9yBQ5jaGVja0dlbmVyYXRvcgQKY2hlY2tDaGFpbgkBGWVuc3VyZU1haW5PckluYWN0aXZlQ2hhaW4BCAUBaQxvcmlnaW5DYWxsZXIDCQAAAgUKY2hlY2tDaGFpbgUKY2hlY2tDaGFpbgQKbmV3Q2hhaW5JZAkAZAIJAQt2YWx1ZU9yRWxzZQIJAJ8IAQUObGFzdENoYWluSWRLZXkAAAABBAluZXdIZWlnaHQJAGQCCAkBCWJsb2NrTWV0YQEFCXJlZmVyZW5jZQJfMQABBAxuZXdCbG9ja01ldGEJAMsBAgkAywECCQDLAQIJAJoDAQUJbmV3SGVpZ2h0CQCaAwEFBmhlaWdodAUJcmVmZXJlbmNlCAgFAWkMb3JpZ2luQ2FsbGVyBWJ5dGVzCQDMCAIJAQtCaW5hcnlFbnRyeQIJAQxibG9ja01ldGFLZXkBBQlibG9ja0hhc2gFDG5ld0Jsb2NrTWV0YQkAzAgCCQELQmluYXJ5RW50cnkCCQEUY2hhaW5GaXJzdEJsb2NrSWRLZXkBBQpuZXdDaGFpbklkBQlibG9ja0hhc2gJAMwIAgkBC0JpbmFyeUVudHJ5AgkBE2NoYWluTGFzdEJsb2NrSWRLZXkBBQpuZXdDaGFpbklkBQlibG9ja0hhc2gJAMwIAgkBC1N0cmluZ0VudHJ5AgkBE2NoYWluQWxsQmxvY2tJZHNLZXkCBQpuZXdDaGFpbklkAAAJANwEAQUJYmxvY2tIYXNoCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEOY2hhaW5IZWlnaHRLZXkBBQpuZXdDaGFpbklkBQluZXdIZWlnaHQJAMwIAgkBDEludGVnZXJFbnRyeQIJAQpjaGFpbklkS2V5AQgIBQFpDG9yaWdpbkNhbGxlcgVieXRlcwUKbmV3Q2hhaW5JZAkAzAgCCQEMc2V0RXBvY2hEYXRhAQgFAWkMb3JpZ2luQ2FsbGVyCQDMCAIJAQtTdHJpbmdFbnRyeQIJAQ1zdXBwb3J0ZXJzS2V5AQUKbmV3Q2hhaW5JZAkApQgBCAUBaQxvcmlnaW5DYWxsZXIJAMwIAgkBDEludGVnZXJFbnRyeQIFGGxhc3RFcG9jaEJsb2Nrc051bWJlcktleQABCQDMCAIJAQxJbnRlZ2VyRW50cnkCBQ5sYXN0Q2hhaW5JZEtleQUKbmV3Q2hhaW5JZAUDbmlsCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBDmV4dGVuZEFsdENoYWluBAdjaGFpbklkCWJsb2NrSGFzaAlyZWZlcmVuY2UFZXBvY2gECmNoZWNrRXBvY2gJARJlbnN1cmVDb3JyZWN0RXBvY2gBBQVlcG9jaAMJAAACBQpjaGVja0Vwb2NoBQpjaGVja0Vwb2NoBA5jaGVja0dlbmVyYXRvcgkBEWVuc3VyZU1pbmluZ0Vwb2NoAQgFAWkMb3JpZ2luQ2FsbGVyAwkAAAIFDmNoZWNrR2VuZXJhdG9yBQ5jaGVja0dlbmVyYXRvcgQKY2hlY2tDaGFpbgkBF2Vuc3VyZUFsdENoYWluRXh0ZW5zaW9uAggFAWkMb3JpZ2luQ2FsbGVyBQdjaGFpbklkAwkAAAIFCmNoZWNrQ2hhaW4FCmNoZWNrQ2hhaW4EDmNoZWNrUmVmZXJlbmNlCQESaXNSZWZlcmVuY2VDb3JyZWN0AgUJcmVmZXJlbmNlCQChCAEJARNjaGFpbkxhc3RCbG9ja0lkS2V5AQUHY2hhaW5JZAMJAAACBQ5jaGVja1JlZmVyZW5jZQUOY2hlY2tSZWZlcmVuY2UEC2NoYWluSGVpZ2h0CQELdmFsdWVPckVsc2UCCQCfCAEJAQ5jaGFpbkhlaWdodEtleQEFB2NoYWluSWQAAAQNYmxvY2tJZHNMYXN0TgkBC3ZhbHVlT3JFbHNlAgkAnwgBCQEYY2hhaW5BbGxCbG9ja0lkc0xhc3ROS2V5AQUHY2hhaW5JZAAABAhibG9ja0lkcwkBEUBleHRyTmF0aXZlKDEwNTgpAQkBE2NoYWluQWxsQmxvY2tJZHNLZXkCBQdjaGFpbklkBQ1ibG9ja0lkc0xhc3ROBAluZXdIZWlnaHQJAGQCBQtjaGFpbkhlaWdodAABBBF1cGRhdGVBbGxCbG9ja0lkcwMJAGcCCQCxAgEFCGJsb2NrSWRzBRNNQVhfQkxPQ0tTX1NUUl9TSVpFCQDMCAIJAQxJbnRlZ2VyRW50cnkCCQEYY2hhaW5BbGxCbG9ja0lkc0xhc3ROS2V5AQUHY2hhaW5JZAkAZAIFDWJsb2NrSWRzTGFzdE4AAQkAzAgCCQELU3RyaW5nRW50cnkCCQETY2hhaW5BbGxCbG9ja0lkc0tleQIFB2NoYWluSWQJAGQCBQ1ibG9ja0lkc0xhc3ROAAEJANwEAQUJYmxvY2tIYXNoBQNuaWwEC25ld0Jsb2NrSWRzCQCsAgIJAKwCAgkA3AQBBQlibG9ja0hhc2gFA1NFUAUIYmxvY2tJZHMJAMwIAgkBC1N0cmluZ0VudHJ5AgkBE2NoYWluQWxsQmxvY2tJZHNLZXkCBQdjaGFpbklkBQ1ibG9ja0lkc0xhc3ROBQtuZXdCbG9ja0lkcwUDbmlsBA5tYWluQ2hhaW5FbnRyeQMJAGYCCQERc3VwcG9ydGluZ0JhbGFuY2UBBQdjaGFpbklkCQBpAgUUY29tcHV0ZWRUb3RhbEJhbGFuY2UAAgkAzAgCCQEMSW50ZWdlckVudHJ5AgUObWFpbkNoYWluSWRLZXkFB2NoYWluSWQFA25pbAUDbmlsBAxuZXdCbG9ja01ldGEJAMsBAgkAywECCQDLAQIJAJoDAQUJbmV3SGVpZ2h0CQCaAwEFBmhlaWdodAUJcmVmZXJlbmNlCAgFAWkMb3JpZ2luQ2FsbGVyBWJ5dGVzCQDOCAIJAM4IAgkAzggCCQDMCAIJAQtCaW5hcnlFbnRyeQIJAQxibG9ja01ldGFLZXkBBQlibG9ja0hhc2gFDG5ld0Jsb2NrTWV0YQkAzAgCCQELQmluYXJ5RW50cnkCCQETY2hhaW5MYXN0QmxvY2tJZEtleQEFB2NoYWluSWQFCWJsb2NrSGFzaAkAzAgCCQEMSW50ZWdlckVudHJ5AgkBDmNoYWluSGVpZ2h0S2V5AQUHY2hhaW5JZAUJbmV3SGVpZ2h0CQDMCAIJAQxzZXRFcG9jaERhdGEBCAUBaQxvcmlnaW5DYWxsZXIJAMwIAgkBDEludGVnZXJFbnRyeQIJAQpjaGFpbklkS2V5AQgIBQFpDG9yaWdpbkNhbGxlcgVieXRlcwUHY2hhaW5JZAkAzAgCCQEMSW50ZWdlckVudHJ5AgUYbGFzdEVwb2NoQmxvY2tzTnVtYmVyS2V5AAEFA25pbAUObWFpbkNoYWluRW50cnkJAQxhZGRTdXBwb3J0ZXICBQdjaGFpbklkCAUBaQxvcmlnaW5DYWxsZXIFEXVwZGF0ZUFsbEJsb2NrSWRzCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBBGpvaW4BDXJld2FyZEFkZHJlc3MKARJjaGVja1Jld2FyZEFkZHJlc3MBB2FkZHJlc3MEByRtYXRjaDAJAKEIAQkBCm1pbmVyUGtLZXkBBQdhZGRyZXNzAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IEAnBrBQckbWF0Y2gwAwkAAAIFAnBrCAUBaRVvcmlnaW5DYWxsZXJQdWJsaWNLZXkFBHVuaXQJAAIBCQCsAgIJAKwCAgkArAICAhFMMiBtaW5lciBhZGRyZXNzIAUHYWRkcmVzcwIYIGlzIGFscmVhZHkgbGlua2VkIHdpdGggCQDYBAEFAnBrBQR1bml0AwkAZgIFC01JTl9CQUxBTkNFCAkA7wcBCAUBaQxvcmlnaW5DYWxsZXIKZ2VuZXJhdGluZwkAAgEJAKwCAgkArAICCQCsAgICIUluc3VmZmljaWVudCBnZW5lcmF0aW5nIGJhbGFuY2U6IAkApAMBCAkA7wcBCAUBaQxvcmlnaW5DYWxsZXIKZ2VuZXJhdGluZwIMLiBSZXF1aXJlZDogCQCkAwEFC01JTl9CQUxBTkNFAwkBAiE9AgkAyAEBBQ1yZXdhcmRBZGRyZXNzABQJAAIBAiVyZXdhcmRBZGRyZXNzIHNob3VsZCBiZSBhbiBMMiBhZGRyZXNz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AQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIJAQUkZjFfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyBBBuZXdMZWF2aW5nTWluZXJzCAUNJHQwMTcwMTExNzEwMQJfMQQJaXNVcGRhdGVkCAUNJHQwMTcwMTExNzEwMQJfMgQWbmV3TGVhdmluZ01pbmVyc0FjdGlvbgMJAQIhPQIFEG5ld0xlYXZpbmdNaW5lcnMFA25pbAkAzAgCCQELU3RyaW5nRW50cnkCCQEQbGVhdmluZ01pbmVyc0tleQEFBmhlaWdodAkAugkCBRBuZXdMZWF2aW5nTWluZXJzBQNTRVAFA25pbAMJAQIhPQIFEGFsbExlYXZpbmdNaW5lcnMFA25pbAkAzAgCCQELRGVsZXRlRW50cnkBCQEQbGVhdmluZ01pbmVyc0tleQEFBmhlaWdodAUDbmlsBQNuaWwECmpvaW5IZWlnaHQDBQlpc1VwZGF0ZWQFBmhlaWdodAkAZAIFBmhlaWdodAABBBhkZWxldGVPbGRSZXdhcmRBZGRyZXNzUGsEByRtYXRjaDAJAKEIAQkBEm1pbmVyUmV3YXJkQWRkcmVzcwEFCG5ld01pbmVyAwkAAQIFByRtYXRjaDACCkJ5dGVWZWN0b3IECm9sZEFkZHJlc3MFByRtYXRjaDADCQAAAgUKb2xkQWRkcmVzcwUNcmV3YXJkQWRkcmVzcwUDbmlsCQDMCAIJAQtEZWxldGVFbnRyeQEJAQptaW5lclBrS2V5AQkA3AQBBQpvbGRBZGRyZXNzBQNuaWwFA25pbAkAzggCCQDOCAIJAMwIAgkBC1N0cmluZ0VudHJ5AgUMYWxsTWluZXJzS2V5BQluZXdNaW5lcnMJAMwIAgkBDEludGVnZXJFbnRyeQIJARJtaW5lckpvaW5IZWlnaHRLZXkBBQhuZXdNaW5lcgUKam9pbkhlaWdodAkAzAgCCQELQmluYXJ5RW50cnkCCQESbWluZXJSZXdhcmRBZGRyZXNzAQUIbmV3TWluZXIFDXJld2FyZEFkZHJlc3MJAMwIAgkBC0JpbmFyeUVudHJ5AgkBCm1pbmVyUGtLZXkBBRByZXdhcmRBZGRyZXNzSGV4CAUBaRVvcmlnaW5DYWxsZXJQdWJsaWNLZXkFA25pbAUWbmV3TGVhdmluZ01pbmVyc0FjdGlvbgUYZGVsZXRlT2xkUmV3YXJkQWRkcmVzc1BrCQACAQIkU3RyaWN0IHZhbHVlIGlzIG5vdCBlcXVhbCB0byBpdHNlbGYuAWkBBWxlYXZlAAQMbGVhdmluZ01pbmVyCQClCAEIBQFpDG9yaWdpbkNhbGxlcgoBC2ZpbHRlck1pbmVyAgNhY2MFbWluZXIDCQAAAgUFbWluZXIFDGxlYXZpbmdNaW5lcgUDYWNjCQDNCAIFA2FjYwUFbWluZXIECnJlc3RNaW5lcnMKAAIkbAUJYWxsTWluZXJzCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQtmaWx0ZXJNaW5lcgIFAiRhCQCRAwIFAiRsBQIkaQoBBSRmMF8yAgIkYQIkaQMJAGcCBQIkaQUCJHMFAiRhCQACAQIUTGlzdCBzaXplIGV4Y2VlZHMgNTAJAQUkZjBfMgIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyAwkAAAIFDnRoaXNFcG9jaE1pbmVyCAgFAWkMb3JpZ2luQ2FsbGVyBWJ5dGVzCQACAQIcZGVzaWduYXRlZCBtaW5lciBjYW4ndCBsZWF2ZQQHJG1hdGNoMAkAnwgBCQESbWluZXJKb2luSGVpZ2h0S2V5AQUMbGVhdmluZ01pbmVyAwkAAQIFByRtYXRjaDACA0ludAQLbWluZXJIZWlnaHQFByRtYXRjaDADCQBmAgULbWluZXJIZWlnaHQFBmhlaWdodAkAzAgCCQELU3RyaW5nRW50cnkCBQxhbGxNaW5lcnNLZXkJALoJAgUKcmVzdE1pbmVycwUDU0VQCQDMCAIJAQtEZWxldGVFbnRyeQEJARJtaW5lckpvaW5IZWlnaHRLZXkBBQxsZWF2aW5nTWluZXIFA25pbAQQb2xkTGVhdmluZ01pbmVycwkBC3ZhbHVlT3JFbHNlAgkAoggBCQEQbGVhdmluZ01pbmVyc0tleQEFBmhlaWdodAIABBBuZXdMZWF2aW5nTWluZXJzAwkAAAIFEG9sZExlYXZpbmdNaW5lcnMCAAUMbGVhdmluZ01pbmVyCQCsAgIJAKwCAgUQb2xkTGVhdmluZ01pbmVycwUDU0VQBQxsZWF2aW5nTWluZXIJAMwIAgkBC1N0cmluZ0VudHJ5AgUMYWxsTWluZXJzS2V5CQC6CQIFCnJlc3RNaW5lcnMFA1NFUAkAzAgCCQELRGVsZXRlRW50cnkBCQESbWluZXJKb2luSGVpZ2h0S2V5AQUMbGVhdmluZ01pbmVyCQDMCAIJAQtTdHJpbmdFbnRyeQIJARBsZWF2aW5nTWluZXJzS2V5AQUGaGVpZ2h0BRBuZXdMZWF2aW5nTWluZXJzBQNuaWwJAMwIAgkBC1N0cmluZ0VudHJ5AgUMYWxsTWluZXJzS2V5CQC6CQIFCnJlc3RNaW5lcnMFA1NFUAUDbmlsAHiFeYA=", "chainId": 84, "height": 3046754, "applicationStatus": "succeeded", "spentComplexity": 0 } View: original | compacted Prev: none Next: 9LVcNq4yYu4tSAK7dib3z1Wimo7hRHSdnK5CvW66kuni Full:
Old | New | Differences | |
---|---|---|---|
1 | - | # no script | |
1 | + | {-# STDLIB_VERSION 8 #-} | |
2 | + | {-# SCRIPT_TYPE ACCOUNT #-} | |
3 | + | {-# CONTENT_TYPE DAPP #-} | |
4 | + | let INT_MAX = 9223372036854775807 | |
5 | + | ||
6 | + | let WAVES = 100000000 | |
7 | + | ||
8 | + | let MIN_BALANCE = (20000 * WAVES) | |
9 | + | ||
10 | + | let MAX_BLOCKS_AT_EPOCH = 50 | |
11 | + | ||
12 | + | let SEP = "," | |
13 | + | ||
14 | + | let BLOCK_HASH_SIZE = 32 | |
15 | + | ||
16 | + | let ADDRESS_SIZE = 26 | |
17 | + | ||
18 | + | let MAX_BLOCKS_STR_SIZE = ((64 * MAX_BLOCKS_AT_EPOCH) + (MAX_BLOCKS_AT_EPOCH - 1)) | |
19 | + | ||
20 | + | let thisEpochDataKey = "thisEpochData" | |
21 | + | ||
22 | + | let allMinersKey = "allMiners" | |
23 | + | ||
24 | + | let mainChainIdKey = "mainChainId" | |
25 | + | ||
26 | + | let lastChainIdKey = "lastChainId" | |
27 | + | ||
28 | + | let lastEpochBlocksNumberKey = "lastEpochBlocksNumber" | |
29 | + | ||
30 | + | let minerRewardKey = "minerReward" | |
31 | + | ||
32 | + | let stakingContractAddress = Address(getBinaryValue(this, "stakingContractAddress")) | |
33 | + | ||
34 | + | func generatingBalance (address) = match getString(stakingContractAddress, ("%s__" + toString(address))) { | |
35 | + | case str: String => | |
36 | + | let paramList = split(str, "__") | |
37 | + | let prevHeight = parseIntValue(paramList[1]) | |
38 | + | let prevBalance = parseIntValue(paramList[2]) | |
39 | + | let nextHeight = parseIntValue(paramList[3]) | |
40 | + | let nextBalance = parseIntValue(paramList[4]) | |
41 | + | if ((height >= nextHeight)) | |
42 | + | then nextBalance | |
43 | + | else if ((height >= prevHeight)) | |
44 | + | then prevBalance | |
45 | + | else 0 | |
46 | + | case _ => | |
47 | + | 0 | |
48 | + | } | |
49 | + | ||
50 | + | ||
51 | + | func blockMetaKey (blockId) = ("blockMeta" + toBase16String(blockId)) | |
52 | + | ||
53 | + | ||
54 | + | func chainIdKey (generator) = ("chainIdOf" + toBase16String(generator)) | |
55 | + | ||
56 | + | ||
57 | + | func chainHeightKey (chainId) = (("chain" + toString(chainId)) + "Height") | |
58 | + | ||
59 | + | ||
60 | + | func chainFirstBlockIdKey (chainId) = (("chain" + toString(chainId)) + "FirstBlock") | |
61 | + | ||
62 | + | ||
63 | + | func chainLastBlockIdKey (chainId) = (("chain" + toString(chainId)) + "LastBlock") | |
64 | + | ||
65 | + | ||
66 | + | func chainAllBlockIdsKey (chainId,n) = ((("chain" + toString(chainId)) + "AllBlocks") + toString(n)) | |
67 | + | ||
68 | + | ||
69 | + | func chainAllBlockIdsLastNKey (chainId) = (("chain" + toString(chainId)) + "AllBlocksLastN") | |
70 | + | ||
71 | + | ||
72 | + | func supportersKey (chainId) = (("chain" + toString(chainId)) + "Supporters") | |
73 | + | ||
74 | + | ||
75 | + | func minerRewardAddress (minerAddr) = (("miner" + minerAddr) + "RewardAddress") | |
76 | + | ||
77 | + | ||
78 | + | func minerJoinHeightKey (minerAddr) = (("miner" + minerAddr) + "JoinHeight") | |
79 | + | ||
80 | + | ||
81 | + | func minerPkKey (rewardAddress) = (("miner" + rewardAddress) + "PK") | |
82 | + | ||
83 | + | ||
84 | + | func leavingMinersKey (epoch) = ("leavingMinersAt" + toString(epoch)) | |
85 | + | ||
86 | + | ||
87 | + | let mainChainId = valueOrElse(getInteger(mainChainIdKey), 0) | |
88 | + | ||
89 | + | let thisEpochMiner = match getString(thisEpochDataKey) { | |
90 | + | case rawThisEpochData: String => | |
91 | + | let thisEpochData = split(rawThisEpochData, SEP) | |
92 | + | let thisEpoch = parseIntValue(thisEpochData[0]) | |
93 | + | if ((thisEpoch == height)) | |
94 | + | then fromBase58String(thisEpochData[1]) | |
95 | + | else unit | |
96 | + | case _ => | |
97 | + | unit | |
98 | + | } | |
99 | + | ||
100 | + | let allMiners = match getString(allMinersKey) { | |
101 | + | case raw: String => | |
102 | + | split_4C(raw, SEP) | |
103 | + | case _ => | |
104 | + | nil | |
105 | + | } | |
106 | + | ||
107 | + | let allLeavingMiners = match getString(leavingMinersKey(height)) { | |
108 | + | case raw: String => | |
109 | + | split_4C(raw, SEP) | |
110 | + | case _ => | |
111 | + | nil | |
112 | + | } | |
113 | + | ||
114 | + | func blockMeta (blockId) = { | |
115 | + | let meta = getBinaryValue(blockMetaKey(blockId)) | |
116 | + | let metaWithoutHeight = drop(meta, 8) | |
117 | + | let metaWithoutHeightEpoch = drop(metaWithoutHeight, 8) | |
118 | + | let blockHeight = toInt(take(meta, 8)) | |
119 | + | let blockEpoch = toInt(take(metaWithoutHeight, 8)) | |
120 | + | let blockParent = take(metaWithoutHeightEpoch, BLOCK_HASH_SIZE) | |
121 | + | let blockGenerator = takeRight(meta, ADDRESS_SIZE) | |
122 | + | $Tuple4(blockHeight, blockEpoch, blockParent, blockGenerator) | |
123 | + | } | |
124 | + | ||
125 | + | ||
126 | + | func setEpochData (generator) = StringEntry(thisEpochDataKey, ((toString(height) + SEP) + toBase58String(generator.bytes))) | |
127 | + | ||
128 | + | ||
129 | + | let $t036534710 = { | |
130 | + | let hitSource = match lastBlock.vrf { | |
131 | + | case vrf: ByteVector => | |
132 | + | vrf | |
133 | + | case _ => | |
134 | + | lastBlock.generationSignature | |
135 | + | } | |
136 | + | func processMiner (prev,miner) = { | |
137 | + | let $t039514014 = prev | |
138 | + | let prevDelay = $t039514014._1 | |
139 | + | let prevMiner = $t039514014._2 | |
140 | + | let prevTotalBalance = $t039514014._3 | |
141 | + | let prevMiners = $t039514014._4 | |
142 | + | let minerAddress = addressFromStringValue(miner) | |
143 | + | let wavesGenBalance = wavesBalance(minerAddress).generating | |
144 | + | let minerBalance = generatingBalance(minerAddress) | |
145 | + | if (if (if ((MIN_BALANCE > wavesGenBalance)) | |
146 | + | then true | |
147 | + | else (0 >= minerBalance)) | |
148 | + | then true | |
149 | + | else (valueOrElse(getInteger(minerJoinHeightKey(miner)), INT_MAX) > height)) | |
150 | + | then prev | |
151 | + | else { | |
152 | + | let nextDelay = calculateDelay(minerAddress, minerBalance) | |
153 | + | if ((prevDelay > nextDelay)) | |
154 | + | then $Tuple4(nextDelay, miner, (prevTotalBalance + minerBalance), (prevMiners :+ miner)) | |
155 | + | else $Tuple4(prevDelay, prevMiner, (prevTotalBalance + minerBalance), (prevMiners :+ miner)) | |
156 | + | } | |
157 | + | } | |
158 | + | ||
159 | + | let $l = (allMiners ++ allLeavingMiners) | |
160 | + | let $s = size($l) | |
161 | + | let $acc0 = $Tuple4(INT_MAX, "", 0, nil) | |
162 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
163 | + | then $a | |
164 | + | else processMiner($a, $l[$i]) | |
165 | + | ||
166 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
167 | + | then $a | |
168 | + | else throw("List size exceeds 50") | |
169 | + | ||
170 | + | $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) | |
171 | + | } | |
172 | + | ||
173 | + | let computedDelay = $t036534710._1 | |
174 | + | ||
175 | + | let computedGenerator = $t036534710._2 | |
176 | + | ||
177 | + | let computedTotalBalance = $t036534710._3 | |
178 | + | ||
179 | + | let filteredMiners = $t036534710._4 | |
180 | + | ||
181 | + | let safeRollbackHeight = { | |
182 | + | func addBalance (acc,blockIdStr) = { | |
183 | + | let $t048244868 = acc | |
184 | + | let totalBalance = $t048244868._1 | |
185 | + | let prevId = $t048244868._2 | |
186 | + | let generators = $t048244868._3 | |
187 | + | if ((totalBalance > (computedTotalBalance / 2))) | |
188 | + | then acc | |
189 | + | else { | |
190 | + | let blockId = fromBase16String(blockIdStr) | |
191 | + | let generator = Address(blockMeta(blockId)._4) | |
192 | + | if (containsElement(generators, generator)) | |
193 | + | then acc | |
194 | + | else { | |
195 | + | let balance = generatingBalance(generator) | |
196 | + | $Tuple3((totalBalance + balance), blockId, (generators :+ generator)) | |
197 | + | } | |
198 | + | } | |
199 | + | } | |
200 | + | ||
201 | + | func getBlockIds (n) = { | |
202 | + | let rawStr = valueOrElse(getString(chainAllBlockIdsKey(mainChainId, n)), "") | |
203 | + | if ((rawStr == "")) | |
204 | + | then nil | |
205 | + | else split_4C(rawStr, SEP) | |
206 | + | } | |
207 | + | ||
208 | + | let lastN = valueOrElse(getInteger(chainAllBlockIdsLastNKey(mainChainId)), 0) | |
209 | + | let allBlocksIds = (((getBlockIds(lastN) ++ getBlockIds((lastN - 1))) ++ getBlockIds((lastN - 2))) ++ getBlockIds((lastN - 3))) | |
210 | + | let $t056365710 = { | |
211 | + | let $l = allBlocksIds | |
212 | + | let $s = size($l) | |
213 | + | let $acc0 = $Tuple3(0, base58'', nil) | |
214 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
215 | + | then $a | |
216 | + | else addBalance($a, $l[$i]) | |
217 | + | ||
218 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
219 | + | then $a | |
220 | + | else throw("List size exceeds 200") | |
221 | + | ||
222 | + | $f0_2($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($f0_1($acc0, 0), 1), 2), 3), 4), 5), 6), 7), 8), 9), 10), 11), 12), 13), 14), 15), 16), 17), 18), 19), 20), 21), 22), 23), 24), 25), 26), 27), 28), 29), 30), 31), 32), 33), 34), 35), 36), 37), 38), 39), 40), 41), 42), 43), 44), 45), 46), 47), 48), 49), 50), 51), 52), 53), 54), 55), 56), 57), 58), 59), 60), 61), 62), 63), 64), 65), 66), 67), 68), 69), 70), 71), 72), 73), 74), 75), 76), 77), 78), 79), 80), 81), 82), 83), 84), 85), 86), 87), 88), 89), 90), 91), 92), 93), 94), 95), 96), 97), 98), 99), 100), 101), 102), 103), 104), 105), 106), 107), 108), 109), 110), 111), 112), 113), 114), 115), 116), 117), 118), 119), 120), 121), 122), 123), 124), 125), 126), 127), 128), 129), 130), 131), 132), 133), 134), 135), 136), 137), 138), 139), 140), 141), 142), 143), 144), 145), 146), 147), 148), 149), 150), 151), 152), 153), 154), 155), 156), 157), 158), 159), 160), 161), 162), 163), 164), 165), 166), 167), 168), 169), 170), 171), 172), 173), 174), 175), 176), 177), 178), 179), 180), 181), 182), 183), 184), 185), 186), 187), 188), 189), 190), 191), 192), 193), 194), 195), 196), 197), 198), 199), 200) | |
223 | + | } | |
224 | + | let _b = $t056365710._1 | |
225 | + | let blockId = $t056365710._2 | |
226 | + | blockMeta(blockId)._1 | |
227 | + | } | |
228 | + | ||
229 | + | func supportingBalance (chainId) = { | |
230 | + | func addBalance (acc,generatorStr) = { | |
231 | + | let $t058555891 = acc | |
232 | + | let totalBalance = $t058555891._1 | |
233 | + | let generators = $t058555891._2 | |
234 | + | let generator = addressFromStringValue(generatorStr) | |
235 | + | if (containsElement(generators, generator)) | |
236 | + | then acc | |
237 | + | else { | |
238 | + | let balance = generatingBalance(generator) | |
239 | + | $Tuple2((totalBalance + balance), (generators :+ generator)) | |
240 | + | } | |
241 | + | } | |
242 | + | ||
243 | + | let allGenerators = split_4C(getStringValue(supportersKey(chainId)), SEP) | |
244 | + | let $t062136278 = { | |
245 | + | let $l = allGenerators | |
246 | + | let $s = size($l) | |
247 | + | let $acc0 = $Tuple2(0, nil) | |
248 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
249 | + | then $a | |
250 | + | else addBalance($a, $l[$i]) | |
251 | + | ||
252 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
253 | + | then $a | |
254 | + | else throw("List size exceeds 100") | |
255 | + | ||
256 | + | $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) | |
257 | + | } | |
258 | + | let balance = $t062136278._1 | |
259 | + | let _g = $t062136278._2 | |
260 | + | balance | |
261 | + | } | |
262 | + | ||
263 | + | ||
264 | + | func ensureMiningEpoch (generator) = if ((toString(generator) != computedGenerator)) | |
265 | + | then throw(((((toBase58String(generator.bytes) + " is not allowed to mine in ") + toString(height)) + " epoch. Expected ") + computedGenerator)) | |
266 | + | else unit | |
267 | + | ||
268 | + | ||
269 | + | func isReferenceCorrect (reference,lastBlock) = match lastBlock { | |
270 | + | case _: Unit => | |
271 | + | unit | |
272 | + | case lb: ByteVector => | |
273 | + | if ((reference == lb)) | |
274 | + | then unit | |
275 | + | else throw(((("Expected a reference to the chain last block: " + toBase16String(lb)) + ". Got: ") + toBase16String(reference))) | |
276 | + | case _ => | |
277 | + | throw("Match error") | |
278 | + | } | |
279 | + | ||
280 | + | ||
281 | + | func chainIsInactive (chainId) = { | |
282 | + | let firstBlockId = getBinaryValue(chainFirstBlockIdKey(chainId)) | |
283 | + | (safeRollbackHeight > blockMeta(firstBlockId)._1) | |
284 | + | } | |
285 | + | ||
286 | + | ||
287 | + | func ensureMainOrInactiveChain (generator) = match getInteger(chainIdKey(generator.bytes)) { | |
288 | + | case currentId: Int => | |
289 | + | if (if ((currentId == mainChainId)) | |
290 | + | then true | |
291 | + | else chainIsInactive(currentId)) | |
292 | + | then unit | |
293 | + | else throw(("miner is mining other chain " + toString(currentId))) | |
294 | + | case _ => | |
295 | + | unit | |
296 | + | } | |
297 | + | ||
298 | + | ||
299 | + | func ensureAltChainExtension (generator,chainId) = match getInteger(chainIdKey(generator.bytes)) { | |
300 | + | case currentId: Int => | |
301 | + | if ((currentId == chainId)) | |
302 | + | then unit | |
303 | + | else { | |
304 | + | let extendingFirstBlockId = getBinaryValue(chainFirstBlockIdKey(chainId)) | |
305 | + | let minerCurrentFirstBlockId = getBinaryValue(chainFirstBlockIdKey(currentId)) | |
306 | + | let extendingFirstBlockHeight = blockMeta(extendingFirstBlockId)._1 | |
307 | + | let minerCurrentFirstBlockHeight = blockMeta(minerCurrentFirstBlockId)._1 | |
308 | + | if ((extendingFirstBlockHeight > minerCurrentFirstBlockHeight)) | |
309 | + | then unit | |
310 | + | else throw(((((("miner is mining other chain " + toString(currentId)) + ", height of the alt chain first block ") + toString(extendingFirstBlockHeight)) + " is not less than height of the miner active chain first block ") + toString(minerCurrentFirstBlockHeight))) | |
311 | + | } | |
312 | + | case _ => | |
313 | + | unit | |
314 | + | } | |
315 | + | ||
316 | + | ||
317 | + | func ensureReferenceIsSafeForRollback (reference) = { | |
318 | + | let startHeight = blockMeta(reference)._1 | |
319 | + | if ((safeRollbackHeight > startHeight)) | |
320 | + | then throw(((("start height " + toString(startHeight)) + " is less than minimum height ") + toString(safeRollbackHeight))) | |
321 | + | else unit | |
322 | + | } | |
323 | + | ||
324 | + | ||
325 | + | func ensureCorrectEpoch (epoch) = if ((epoch == height)) | |
326 | + | then unit | |
327 | + | else throw(((("Expected block from epoch " + toString(height)) + ". Got ") + toString(epoch))) | |
328 | + | ||
329 | + | ||
330 | + | func checkBlocksNumber () = if ((MAX_BLOCKS_AT_EPOCH > getIntegerValue(lastEpochBlocksNumberKey))) | |
331 | + | then unit | |
332 | + | else throw("Max blocks number at epoch reached") | |
333 | + | ||
334 | + | ||
335 | + | func addSupporter (chainId,generator) = { | |
336 | + | let supportersStr = getStringValue(supportersKey(chainId)) | |
337 | + | let supporters = split(supportersStr, SEP) | |
338 | + | if (containsElement(supporters, toString(generator))) | |
339 | + | then nil | |
340 | + | else [StringEntry(supportersKey(chainId), ((supportersStr + SEP) + toString(generator)))] | |
341 | + | } | |
342 | + | ||
343 | + | ||
344 | + | @Callable(i) | |
345 | + | func appendBlock (blockHash,reference) = { | |
346 | + | let check = checkBlocksNumber() | |
347 | + | if ((check == check)) | |
348 | + | then if ((thisEpochMiner != i.originCaller.bytes)) | |
349 | + | then match thisEpochMiner { | |
350 | + | case epochMiner: ByteVector => | |
351 | + | throw(("not allowed to forge blocks in this epoch, expected from " + toBase58String(epochMiner))) | |
352 | + | case _ => | |
353 | + | throw("not allowed to forge blocks in this epoch, epoch miner is absent") | |
354 | + | } | |
355 | + | else { | |
356 | + | let chainId = valueOrElse(getInteger(chainIdKey(i.originCaller.bytes)), mainChainId) | |
357 | + | let lastBlockId = getBinaryValue(chainLastBlockIdKey(chainId)) | |
358 | + | let check2 = isReferenceCorrect(reference, lastBlockId) | |
359 | + | if ((check2 == check2)) | |
360 | + | then { | |
361 | + | let chainHeight = valueOrElse(getInteger(chainHeightKey(chainId)), 0) | |
362 | + | let newHeight = (chainHeight + 1) | |
363 | + | let blocksNumber = valueOrElse(getInteger(lastEpochBlocksNumberKey), 0) | |
364 | + | let newBlockMeta = (((toBytes(newHeight) + toBytes(height)) + lastBlockId) + i.originCaller.bytes) | |
365 | + | [BinaryEntry(blockMetaKey(blockHash), newBlockMeta), IntegerEntry(chainHeightKey(chainId), newHeight), BinaryEntry(chainLastBlockIdKey(chainId), blockHash), IntegerEntry(lastEpochBlocksNumberKey, (blocksNumber + 1))] | |
366 | + | } | |
367 | + | else throw("Strict value is not equal to itself.") | |
368 | + | } | |
369 | + | else throw("Strict value is not equal to itself.") | |
370 | + | } | |
371 | + | ||
372 | + | ||
373 | + | ||
374 | + | @Callable(i) | |
375 | + | func extendMainChain (blockHash,reference,epoch) = { | |
376 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
377 | + | if ((checkEpoch == checkEpoch)) | |
378 | + | then { | |
379 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
380 | + | if ((checkGenerator == checkGenerator)) | |
381 | + | then { | |
382 | + | let checkChain = ensureMainOrInactiveChain(i.originCaller) | |
383 | + | if ((checkChain == checkChain)) | |
384 | + | then { | |
385 | + | let chainHeight = valueOrElse(getInteger(chainHeightKey(mainChainId)), 0) | |
386 | + | let lastValidBlockId = getBinary(chainLastBlockIdKey(mainChainId)) | |
387 | + | let checkReference = isReferenceCorrect(reference, lastValidBlockId) | |
388 | + | if ((checkReference == checkReference)) | |
389 | + | then { | |
390 | + | let blockIdsLastN = valueOrElse(getInteger(chainAllBlockIdsLastNKey(mainChainId)), 0) | |
391 | + | let blockIds = valueOrElse(getString(chainAllBlockIdsKey(mainChainId, blockIdsLastN)), "") | |
392 | + | let newHeight = (chainHeight + 1) | |
393 | + | let updateAllBlockIds = if ((size(blockIds) >= MAX_BLOCKS_STR_SIZE)) | |
394 | + | then [IntegerEntry(chainAllBlockIdsLastNKey(mainChainId), (blockIdsLastN + 1)), StringEntry(chainAllBlockIdsKey(mainChainId, (blockIdsLastN + 1)), toBase16String(blockHash))] | |
395 | + | else { | |
396 | + | let newBlockIds = if ((blockIds == "")) | |
397 | + | then toBase16String(blockHash) | |
398 | + | else ((toBase16String(blockHash) + SEP) + blockIds) | |
399 | + | [StringEntry(chainAllBlockIdsKey(mainChainId, blockIdsLastN), newBlockIds)] | |
400 | + | } | |
401 | + | let firstBlockId = match lastValidBlockId { | |
402 | + | case id: ByteVector => | |
403 | + | nil | |
404 | + | case _ => | |
405 | + | [BinaryEntry(chainFirstBlockIdKey(mainChainId), blockHash)] | |
406 | + | } | |
407 | + | let newBlockMeta = (((toBytes(newHeight) + toBytes(height)) + reference) + i.originCaller.bytes) | |
408 | + | (([BinaryEntry(blockMetaKey(blockHash), newBlockMeta), IntegerEntry(chainHeightKey(mainChainId), newHeight), BinaryEntry(chainLastBlockIdKey(mainChainId), blockHash), IntegerEntry(chainIdKey(i.originCaller.bytes), mainChainId), setEpochData(i.originCaller), IntegerEntry(lastEpochBlocksNumberKey, 1)] ++ firstBlockId) ++ updateAllBlockIds) | |
409 | + | } | |
410 | + | else throw("Strict value is not equal to itself.") | |
411 | + | } | |
412 | + | else throw("Strict value is not equal to itself.") | |
413 | + | } | |
414 | + | else throw("Strict value is not equal to itself.") | |
415 | + | } | |
416 | + | else throw("Strict value is not equal to itself.") | |
417 | + | } | |
418 | + | ||
419 | + | ||
420 | + | ||
421 | + | @Callable(i) | |
422 | + | func startAltChain (blockHash,reference,epoch) = { | |
423 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
424 | + | if ((checkEpoch == checkEpoch)) | |
425 | + | then { | |
426 | + | let checkReference = ensureReferenceIsSafeForRollback(reference) | |
427 | + | if ((checkReference == checkReference)) | |
428 | + | then { | |
429 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
430 | + | if ((checkGenerator == checkGenerator)) | |
431 | + | then { | |
432 | + | let checkChain = ensureMainOrInactiveChain(i.originCaller) | |
433 | + | if ((checkChain == checkChain)) | |
434 | + | then { | |
435 | + | let newChainId = (valueOrElse(getInteger(lastChainIdKey), 0) + 1) | |
436 | + | let newHeight = (blockMeta(reference)._1 + 1) | |
437 | + | let newBlockMeta = (((toBytes(newHeight) + toBytes(height)) + reference) + i.originCaller.bytes) | |
438 | + | [BinaryEntry(blockMetaKey(blockHash), newBlockMeta), BinaryEntry(chainFirstBlockIdKey(newChainId), blockHash), BinaryEntry(chainLastBlockIdKey(newChainId), blockHash), StringEntry(chainAllBlockIdsKey(newChainId, 0), toBase16String(blockHash)), IntegerEntry(chainHeightKey(newChainId), newHeight), IntegerEntry(chainIdKey(i.originCaller.bytes), newChainId), setEpochData(i.originCaller), StringEntry(supportersKey(newChainId), toString(i.originCaller)), IntegerEntry(lastEpochBlocksNumberKey, 1), IntegerEntry(lastChainIdKey, newChainId)] | |
439 | + | } | |
440 | + | else throw("Strict value is not equal to itself.") | |
441 | + | } | |
442 | + | else throw("Strict value is not equal to itself.") | |
443 | + | } | |
444 | + | else throw("Strict value is not equal to itself.") | |
445 | + | } | |
446 | + | else throw("Strict value is not equal to itself.") | |
447 | + | } | |
448 | + | ||
449 | + | ||
450 | + | ||
451 | + | @Callable(i) | |
452 | + | func extendAltChain (chainId,blockHash,reference,epoch) = { | |
453 | + | let checkEpoch = ensureCorrectEpoch(epoch) | |
454 | + | if ((checkEpoch == checkEpoch)) | |
455 | + | then { | |
456 | + | let checkGenerator = ensureMiningEpoch(i.originCaller) | |
457 | + | if ((checkGenerator == checkGenerator)) | |
458 | + | then { | |
459 | + | let checkChain = ensureAltChainExtension(i.originCaller, chainId) | |
460 | + | if ((checkChain == checkChain)) | |
461 | + | then { | |
462 | + | let checkReference = isReferenceCorrect(reference, getBinary(chainLastBlockIdKey(chainId))) | |
463 | + | if ((checkReference == checkReference)) | |
464 | + | then { | |
465 | + | let chainHeight = valueOrElse(getInteger(chainHeightKey(chainId)), 0) | |
466 | + | let blockIdsLastN = valueOrElse(getInteger(chainAllBlockIdsLastNKey(chainId)), 0) | |
467 | + | let blockIds = getStringValue(chainAllBlockIdsKey(chainId, blockIdsLastN)) | |
468 | + | let newHeight = (chainHeight + 1) | |
469 | + | let updateAllBlockIds = if ((size(blockIds) >= MAX_BLOCKS_STR_SIZE)) | |
470 | + | then [IntegerEntry(chainAllBlockIdsLastNKey(chainId), (blockIdsLastN + 1)), StringEntry(chainAllBlockIdsKey(chainId, (blockIdsLastN + 1)), toBase16String(blockHash))] | |
471 | + | else { | |
472 | + | let newBlockIds = ((toBase16String(blockHash) + SEP) + blockIds) | |
473 | + | [StringEntry(chainAllBlockIdsKey(chainId, blockIdsLastN), newBlockIds)] | |
474 | + | } | |
475 | + | let mainChainEntry = if ((supportingBalance(chainId) > (computedTotalBalance / 2))) | |
476 | + | then [IntegerEntry(mainChainIdKey, chainId)] | |
477 | + | else nil | |
478 | + | let newBlockMeta = (((toBytes(newHeight) + toBytes(height)) + reference) + i.originCaller.bytes) | |
479 | + | ((([BinaryEntry(blockMetaKey(blockHash), newBlockMeta), BinaryEntry(chainLastBlockIdKey(chainId), blockHash), IntegerEntry(chainHeightKey(chainId), newHeight), setEpochData(i.originCaller), IntegerEntry(chainIdKey(i.originCaller.bytes), chainId), IntegerEntry(lastEpochBlocksNumberKey, 1)] ++ mainChainEntry) ++ addSupporter(chainId, i.originCaller)) ++ updateAllBlockIds) | |
480 | + | } | |
481 | + | else throw("Strict value is not equal to itself.") | |
482 | + | } | |
483 | + | else throw("Strict value is not equal to itself.") | |
484 | + | } | |
485 | + | else throw("Strict value is not equal to itself.") | |
486 | + | } | |
487 | + | else throw("Strict value is not equal to itself.") | |
488 | + | } | |
489 | + | ||
490 | + | ||
491 | + | ||
492 | + | @Callable(i) | |
493 | + | func join (rewardAddress) = { | |
494 | + | func checkRewardAddress (address) = match getBinary(minerPkKey(address)) { | |
495 | + | case pk: ByteVector => | |
496 | + | if ((pk == i.originCallerPublicKey)) | |
497 | + | then unit | |
498 | + | else throw(((("L2 miner address " + address) + " is already linked with ") + toBase58String(pk))) | |
499 | + | case _ => | |
500 | + | unit | |
501 | + | } | |
502 | + | ||
503 | + | if ((MIN_BALANCE > wavesBalance(i.originCaller).generating)) | |
504 | + | then throw(((("Insufficient generating balance: " + toString(wavesBalance(i.originCaller).generating)) + ". Required: ") + toString(MIN_BALANCE))) | |
505 | + | else if ((size(rewardAddress) != 20)) | |
506 | + | then throw("rewardAddress should be an L2 address") | |
507 | + | else { | |
508 | + | func checkExistence (exists,miner) = if (exists) | |
509 | + | then true | |
510 | + | else (miner == toString(i.originCaller)) | |
511 | + | ||
512 | + | let alreadyExists = { | |
513 | + | let $l = allMiners | |
514 | + | let $s = size($l) | |
515 | + | let $acc0 = false | |
516 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
517 | + | then $a | |
518 | + | else checkExistence($a, $l[$i]) | |
519 | + | ||
520 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
521 | + | then $a | |
522 | + | else throw("List size exceeds 50") | |
523 | + | ||
524 | + | $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) | |
525 | + | } | |
526 | + | if (alreadyExists) | |
527 | + | then nil | |
528 | + | else { | |
529 | + | let newMiner = toString(i.originCaller) | |
530 | + | let rewardAddressHex = toBase16String(rewardAddress) | |
531 | + | let check = checkRewardAddress(rewardAddressHex) | |
532 | + | if ((check == check)) | |
533 | + | then { | |
534 | + | func filterLeaving (acc,miner) = { | |
535 | + | let $t01671516747 = acc | |
536 | + | let accMiners = $t01671516747._1 | |
537 | + | let isUpdated = $t01671516747._2 | |
538 | + | if ((miner == newMiner)) | |
539 | + | then $Tuple2(accMiners, true) | |
540 | + | else $Tuple2((accMiners :+ miner), isUpdated) | |
541 | + | } | |
542 | + | ||
543 | + | let newMiners = if ((size(allMiners) == 0)) | |
544 | + | then newMiner | |
545 | + | else ((makeString_2C(allMiners, SEP) + SEP) + newMiner) | |
546 | + | let $t01701117101 = { | |
547 | + | let $l = allLeavingMiners | |
548 | + | let $s = size($l) | |
549 | + | let $acc0 = $Tuple2(nil, false) | |
550 | + | func $f1_1 ($a,$i) = if (($i >= $s)) | |
551 | + | then $a | |
552 | + | else filterLeaving($a, $l[$i]) | |
553 | + | ||
554 | + | func $f1_2 ($a,$i) = if (($i >= $s)) | |
555 | + | then $a | |
556 | + | else throw("List size exceeds 50") | |
557 | + | ||
558 | + | $f1_2($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_1($f1_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) | |
559 | + | } | |
560 | + | let newLeavingMiners = $t01701117101._1 | |
561 | + | let isUpdated = $t01701117101._2 | |
562 | + | let newLeavingMinersAction = if ((newLeavingMiners != nil)) | |
563 | + | then [StringEntry(leavingMinersKey(height), makeString_2C(newLeavingMiners, SEP))] | |
564 | + | else if ((allLeavingMiners != nil)) | |
565 | + | then [DeleteEntry(leavingMinersKey(height))] | |
566 | + | else nil | |
567 | + | let joinHeight = if (isUpdated) | |
568 | + | then height | |
569 | + | else (height + 1) | |
570 | + | let deleteOldRewardAddressPk = match getBinary(minerRewardAddress(newMiner)) { | |
571 | + | case oldAddress: ByteVector => | |
572 | + | if ((oldAddress == rewardAddress)) | |
573 | + | then nil | |
574 | + | else [DeleteEntry(minerPkKey(toBase16String(oldAddress)))] | |
575 | + | case _ => | |
576 | + | nil | |
577 | + | } | |
578 | + | (([StringEntry(allMinersKey, newMiners), IntegerEntry(minerJoinHeightKey(newMiner), joinHeight), BinaryEntry(minerRewardAddress(newMiner), rewardAddress), BinaryEntry(minerPkKey(rewardAddressHex), i.originCallerPublicKey)] ++ newLeavingMinersAction) ++ deleteOldRewardAddressPk) | |
579 | + | } | |
580 | + | else throw("Strict value is not equal to itself.") | |
581 | + | } | |
582 | + | } | |
583 | + | } | |
584 | + | ||
585 | + | ||
586 | + | ||
587 | + | @Callable(i) | |
588 | + | func leave () = { | |
589 | + | let leavingMiner = toString(i.originCaller) | |
590 | + | func filterMiner (acc,miner) = if ((miner == leavingMiner)) | |
591 | + | then acc | |
592 | + | else (acc :+ miner) | |
593 | + | ||
594 | + | let restMiners = { | |
595 | + | let $l = allMiners | |
596 | + | let $s = size($l) | |
597 | + | let $acc0 = nil | |
598 | + | func $f0_1 ($a,$i) = if (($i >= $s)) | |
599 | + | then $a | |
600 | + | else filterMiner($a, $l[$i]) | |
601 | + | ||
602 | + | func $f0_2 ($a,$i) = if (($i >= $s)) | |
603 | + | then $a | |
604 | + | else throw("List size exceeds 50") | |
605 | + | ||
606 | + | $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) | |
607 | + | } | |
608 | + | if ((thisEpochMiner == i.originCaller.bytes)) | |
609 | + | then throw("designated miner can't leave") | |
610 | + | else match getInteger(minerJoinHeightKey(leavingMiner)) { | |
611 | + | case minerHeight: Int => | |
612 | + | if ((minerHeight > height)) | |
613 | + | then [StringEntry(allMinersKey, makeString_2C(restMiners, SEP)), DeleteEntry(minerJoinHeightKey(leavingMiner))] | |
614 | + | else { | |
615 | + | let oldLeavingMiners = valueOrElse(getString(leavingMinersKey(height)), "") | |
616 | + | let newLeavingMiners = if ((oldLeavingMiners == "")) | |
617 | + | then leavingMiner | |
618 | + | else ((oldLeavingMiners + SEP) + leavingMiner) | |
619 | + | [StringEntry(allMinersKey, makeString_2C(restMiners, SEP)), DeleteEntry(minerJoinHeightKey(leavingMiner)), StringEntry(leavingMinersKey(height), newLeavingMiners)] | |
620 | + | } | |
621 | + | case _ => | |
622 | + | [StringEntry(allMinersKey, makeString_2C(restMiners, SEP))] | |
623 | + | } | |
624 | + | } | |
625 | + | ||
626 | + |
github/deemru/w8io/169f3d6 42.29 ms ◑![]()