From 212706217e330fe09e97ccc21fa37c0bd15df068 Mon Sep 17 00:00:00 2001 From: Mitch Date: Fri, 6 Sep 2024 14:13:47 -0400 Subject: [PATCH 1/8] add spartan terraform --- .gitignore | 1 + spartan/iac/main.tf | 125 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 spartan/iac/main.tf diff --git a/.gitignore b/.gitignore index 71f1e37b5e2..9a2dd48b704 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ build/ .idea cmake-build-debug .terraform* +terraform.tfstate* .bootstrapped .tsbuildinfo diff --git a/spartan/iac/main.tf b/spartan/iac/main.tf new file mode 100644 index 00000000000..8174abc71be --- /dev/null +++ b/spartan/iac/main.tf @@ -0,0 +1,125 @@ +# Configure the AWS Provider +provider "aws" { + region = "us-east-2" # Change this to your preferred region +} + +# Create VPC for EKS +resource "aws_vpc" "spartan_vpc" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = "spartan-vpc" + } +} + +# Create an internet gateway +resource "aws_internet_gateway" "spartan_igw" { + vpc_id = aws_vpc.spartan_vpc.id + + tags = { + Name = "spartan-igw" + } +} + +# Create a subnet +resource "aws_subnet" "spartan_subnet" { + vpc_id = aws_vpc.spartan_vpc.id + cidr_block = "10.0.1.0/24" + availability_zone = "us-east-2a" # Change this to match your region + + tags = { + Name = "spartan-subnet" + } +} + +# Create EKS Cluster +resource "aws_eks_cluster" "spartan_cluster" { + name = "spartan-cluster" + role_arn = aws_iam_role.spartan_cluster_role.arn + + vpc_config { + subnet_ids = [aws_subnet.spartan_subnet.id] + } + + depends_on = [aws_iam_role_policy_attachment.spartan_cluster_policy] +} + +# Create IAM role for EKS Cluster +resource "aws_iam_role" "spartan_cluster_role" { + name = "spartan-cluster-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "eks.amazonaws.com" + } + } + ] + }) +} + +# Attach necessary policies to the EKS Cluster role +resource "aws_iam_role_policy_attachment" "spartan_cluster_policy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" + role = aws_iam_role.spartan_cluster_role.name +} + +# Create EKS Node Group +resource "aws_eks_node_group" "spartan_node_group" { + cluster_name = aws_eks_cluster.spartan_cluster.name + node_group_name = "spartan-node-group" + node_role_arn = aws_iam_role.spartan_node_role.arn + subnet_ids = [aws_subnet.spartan_subnet.id] + + scaling_config { + desired_size = 1 + max_size = 1 + min_size = 1 + } + + instance_types = ["t4g.2xlarge"] + + depends_on = [ + aws_iam_role_policy_attachment.spartan_worker_node_policy, + aws_iam_role_policy_attachment.spartan_cni_policy, + aws_iam_role_policy_attachment.spartan_ecr_policy, + ] +} + +# Create IAM role for EKS Node Group +resource "aws_iam_role" "spartan_node_role" { + name = "spartan-node-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "ec2.amazonaws.com" + } + } + ] + }) +} + +# Attach necessary policies to the EKS Node role +resource "aws_iam_role_policy_attachment" "spartan_worker_node_policy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" + role = aws_iam_role.spartan_node_role.name +} + +resource "aws_iam_role_policy_attachment" "spartan_cni_policy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" + role = aws_iam_role.spartan_node_role.name +} + +resource "aws_iam_role_policy_attachment" "spartan_ecr_policy" { + policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" + role = aws_iam_role.spartan_node_role.name +} \ No newline at end of file From e76a50e4d6c89bf7f729b65f0ed7395b5276cbcb Mon Sep 17 00:00:00 2001 From: Mitch Date: Fri, 6 Sep 2024 15:56:00 -0400 Subject: [PATCH 2/8] consolidate code --- {helm-charts/aztec-network => spartan/helm-chart}/.helmignore | 0 {helm-charts/aztec-network => spartan/helm-chart}/Chart.yaml | 0 .../helm-chart}/files/config/config-prover-env.sh | 0 .../helm-chart}/files/config/config-validator-env.sh | 0 .../grafana_dashboards/aztec/aztec-dashboard-all-in-one.json | 0 .../helm-chart}/files/grafana_dashboards/default.yml | 0 .../helm-chart}/templates/_helpers.tpl | 0 .../helm-chart}/templates/anvil.deployment.yaml | 0 .../helm-chart}/templates/anvil.service.yaml | 0 .../helm-chart}/templates/boot-node.service.yaml | 0 .../helm-chart}/templates/boot-node.stateful-set.yaml | 0 .../helm-chart}/templates/deploy-contracts.config-map.yaml | 0 .../helm-chart}/templates/deploy-l2-contracts.job.yaml | 0 .../helm-chart}/templates/metrics.yaml | 0 .../helm-chart}/templates/prover-node.service.yaml | 0 .../helm-chart}/templates/prover-node.stateful-set.yaml | 0 .../helm-chart}/templates/pxe.deployment.yaml | 0 .../helm-chart}/templates/pxe.service.yaml | 0 .../helm-chart}/templates/tests/run-tests.yaml | 0 .../helm-chart}/templates/validator.service.yaml | 0 .../helm-chart}/templates/validator.stateful-set.yaml | 0 {helm-charts/aztec-network => spartan/helm-chart}/values.yaml | 0 .../helm-chart}/values/3-validators.yaml | 0 .../aztec-network => spartan/helm-chart}/values/default.yaml | 0 .../end-to-end => spartan}/scripts/create_k8s_dashboard.sh | 0 .../end-to-end => spartan}/scripts/forward_k8s_dashboard.sh | 0 .../end-to-end => spartan}/scripts/setup_local_k8s.sh | 0 yarn-project/end-to-end/Earthfile | 4 ++-- 28 files changed, 2 insertions(+), 2 deletions(-) rename {helm-charts/aztec-network => spartan/helm-chart}/.helmignore (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/Chart.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/files/config/config-prover-env.sh (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/files/config/config-validator-env.sh (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/files/grafana_dashboards/aztec/aztec-dashboard-all-in-one.json (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/files/grafana_dashboards/default.yml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/_helpers.tpl (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/anvil.deployment.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/anvil.service.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/boot-node.service.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/boot-node.stateful-set.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/deploy-contracts.config-map.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/deploy-l2-contracts.job.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/metrics.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/prover-node.service.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/prover-node.stateful-set.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/pxe.deployment.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/pxe.service.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/tests/run-tests.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/validator.service.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/templates/validator.stateful-set.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/values.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/values/3-validators.yaml (100%) rename {helm-charts/aztec-network => spartan/helm-chart}/values/default.yaml (100%) rename {yarn-project/end-to-end => spartan}/scripts/create_k8s_dashboard.sh (100%) rename {yarn-project/end-to-end => spartan}/scripts/forward_k8s_dashboard.sh (100%) rename {yarn-project/end-to-end => spartan}/scripts/setup_local_k8s.sh (100%) diff --git a/helm-charts/aztec-network/.helmignore b/spartan/helm-chart/.helmignore similarity index 100% rename from helm-charts/aztec-network/.helmignore rename to spartan/helm-chart/.helmignore diff --git a/helm-charts/aztec-network/Chart.yaml b/spartan/helm-chart/Chart.yaml similarity index 100% rename from helm-charts/aztec-network/Chart.yaml rename to spartan/helm-chart/Chart.yaml diff --git a/helm-charts/aztec-network/files/config/config-prover-env.sh b/spartan/helm-chart/files/config/config-prover-env.sh similarity index 100% rename from helm-charts/aztec-network/files/config/config-prover-env.sh rename to spartan/helm-chart/files/config/config-prover-env.sh diff --git a/helm-charts/aztec-network/files/config/config-validator-env.sh b/spartan/helm-chart/files/config/config-validator-env.sh similarity index 100% rename from helm-charts/aztec-network/files/config/config-validator-env.sh rename to spartan/helm-chart/files/config/config-validator-env.sh diff --git a/helm-charts/aztec-network/files/grafana_dashboards/aztec/aztec-dashboard-all-in-one.json b/spartan/helm-chart/files/grafana_dashboards/aztec/aztec-dashboard-all-in-one.json similarity index 100% rename from helm-charts/aztec-network/files/grafana_dashboards/aztec/aztec-dashboard-all-in-one.json rename to spartan/helm-chart/files/grafana_dashboards/aztec/aztec-dashboard-all-in-one.json diff --git a/helm-charts/aztec-network/files/grafana_dashboards/default.yml b/spartan/helm-chart/files/grafana_dashboards/default.yml similarity index 100% rename from helm-charts/aztec-network/files/grafana_dashboards/default.yml rename to spartan/helm-chart/files/grafana_dashboards/default.yml diff --git a/helm-charts/aztec-network/templates/_helpers.tpl b/spartan/helm-chart/templates/_helpers.tpl similarity index 100% rename from helm-charts/aztec-network/templates/_helpers.tpl rename to spartan/helm-chart/templates/_helpers.tpl diff --git a/helm-charts/aztec-network/templates/anvil.deployment.yaml b/spartan/helm-chart/templates/anvil.deployment.yaml similarity index 100% rename from helm-charts/aztec-network/templates/anvil.deployment.yaml rename to spartan/helm-chart/templates/anvil.deployment.yaml diff --git a/helm-charts/aztec-network/templates/anvil.service.yaml b/spartan/helm-chart/templates/anvil.service.yaml similarity index 100% rename from helm-charts/aztec-network/templates/anvil.service.yaml rename to spartan/helm-chart/templates/anvil.service.yaml diff --git a/helm-charts/aztec-network/templates/boot-node.service.yaml b/spartan/helm-chart/templates/boot-node.service.yaml similarity index 100% rename from helm-charts/aztec-network/templates/boot-node.service.yaml rename to spartan/helm-chart/templates/boot-node.service.yaml diff --git a/helm-charts/aztec-network/templates/boot-node.stateful-set.yaml b/spartan/helm-chart/templates/boot-node.stateful-set.yaml similarity index 100% rename from helm-charts/aztec-network/templates/boot-node.stateful-set.yaml rename to spartan/helm-chart/templates/boot-node.stateful-set.yaml diff --git a/helm-charts/aztec-network/templates/deploy-contracts.config-map.yaml b/spartan/helm-chart/templates/deploy-contracts.config-map.yaml similarity index 100% rename from helm-charts/aztec-network/templates/deploy-contracts.config-map.yaml rename to spartan/helm-chart/templates/deploy-contracts.config-map.yaml diff --git a/helm-charts/aztec-network/templates/deploy-l2-contracts.job.yaml b/spartan/helm-chart/templates/deploy-l2-contracts.job.yaml similarity index 100% rename from helm-charts/aztec-network/templates/deploy-l2-contracts.job.yaml rename to spartan/helm-chart/templates/deploy-l2-contracts.job.yaml diff --git a/helm-charts/aztec-network/templates/metrics.yaml b/spartan/helm-chart/templates/metrics.yaml similarity index 100% rename from helm-charts/aztec-network/templates/metrics.yaml rename to spartan/helm-chart/templates/metrics.yaml diff --git a/helm-charts/aztec-network/templates/prover-node.service.yaml b/spartan/helm-chart/templates/prover-node.service.yaml similarity index 100% rename from helm-charts/aztec-network/templates/prover-node.service.yaml rename to spartan/helm-chart/templates/prover-node.service.yaml diff --git a/helm-charts/aztec-network/templates/prover-node.stateful-set.yaml b/spartan/helm-chart/templates/prover-node.stateful-set.yaml similarity index 100% rename from helm-charts/aztec-network/templates/prover-node.stateful-set.yaml rename to spartan/helm-chart/templates/prover-node.stateful-set.yaml diff --git a/helm-charts/aztec-network/templates/pxe.deployment.yaml b/spartan/helm-chart/templates/pxe.deployment.yaml similarity index 100% rename from helm-charts/aztec-network/templates/pxe.deployment.yaml rename to spartan/helm-chart/templates/pxe.deployment.yaml diff --git a/helm-charts/aztec-network/templates/pxe.service.yaml b/spartan/helm-chart/templates/pxe.service.yaml similarity index 100% rename from helm-charts/aztec-network/templates/pxe.service.yaml rename to spartan/helm-chart/templates/pxe.service.yaml diff --git a/helm-charts/aztec-network/templates/tests/run-tests.yaml b/spartan/helm-chart/templates/tests/run-tests.yaml similarity index 100% rename from helm-charts/aztec-network/templates/tests/run-tests.yaml rename to spartan/helm-chart/templates/tests/run-tests.yaml diff --git a/helm-charts/aztec-network/templates/validator.service.yaml b/spartan/helm-chart/templates/validator.service.yaml similarity index 100% rename from helm-charts/aztec-network/templates/validator.service.yaml rename to spartan/helm-chart/templates/validator.service.yaml diff --git a/helm-charts/aztec-network/templates/validator.stateful-set.yaml b/spartan/helm-chart/templates/validator.stateful-set.yaml similarity index 100% rename from helm-charts/aztec-network/templates/validator.stateful-set.yaml rename to spartan/helm-chart/templates/validator.stateful-set.yaml diff --git a/helm-charts/aztec-network/values.yaml b/spartan/helm-chart/values.yaml similarity index 100% rename from helm-charts/aztec-network/values.yaml rename to spartan/helm-chart/values.yaml diff --git a/helm-charts/aztec-network/values/3-validators.yaml b/spartan/helm-chart/values/3-validators.yaml similarity index 100% rename from helm-charts/aztec-network/values/3-validators.yaml rename to spartan/helm-chart/values/3-validators.yaml diff --git a/helm-charts/aztec-network/values/default.yaml b/spartan/helm-chart/values/default.yaml similarity index 100% rename from helm-charts/aztec-network/values/default.yaml rename to spartan/helm-chart/values/default.yaml diff --git a/yarn-project/end-to-end/scripts/create_k8s_dashboard.sh b/spartan/scripts/create_k8s_dashboard.sh similarity index 100% rename from yarn-project/end-to-end/scripts/create_k8s_dashboard.sh rename to spartan/scripts/create_k8s_dashboard.sh diff --git a/yarn-project/end-to-end/scripts/forward_k8s_dashboard.sh b/spartan/scripts/forward_k8s_dashboard.sh similarity index 100% rename from yarn-project/end-to-end/scripts/forward_k8s_dashboard.sh rename to spartan/scripts/forward_k8s_dashboard.sh diff --git a/yarn-project/end-to-end/scripts/setup_local_k8s.sh b/spartan/scripts/setup_local_k8s.sh similarity index 100% rename from yarn-project/end-to-end/scripts/setup_local_k8s.sh rename to spartan/scripts/setup_local_k8s.sh diff --git a/yarn-project/end-to-end/Earthfile b/yarn-project/end-to-end/Earthfile index b59dbd47986..73a71fe6a8a 100644 --- a/yarn-project/end-to-end/Earthfile +++ b/yarn-project/end-to-end/Earthfile @@ -92,10 +92,10 @@ NETWORK_TEST: RUN kubectl delete namespace $namespace --ignore-not-found=true --wait=true --now --timeout=10m END - RUN helm install spartan ../../helm-charts/aztec-network \ + RUN helm install spartan ../../spartan/helm-chart/ \ --namespace $namespace \ --create-namespace \ - --values ../../helm-charts/aztec-network/values/$values_file \ + --values ../../spartan/helm-chart/values/$values_file \ --set images.test.image="aztecprotocol/end-to-end:$AZTEC_DOCKER_TAG" \ --set images.aztec.image="aztecprotocol/aztec:$AZTEC_DOCKER_TAG" \ --set test="$test" \ From 4882250284f952e29a294f6c1441b56f9cf6a300 Mon Sep 17 00:00:00 2001 From: Mitch Date: Fri, 6 Sep 2024 17:10:38 -0400 Subject: [PATCH 3/8] move more around. create metrics chart --- .../{helm-chart => aztec-network}/.helmignore | 0 .../{helm-chart => aztec-network}/Chart.yaml | 0 .../files/config/config-prover-env.sh | 0 .../files/config/config-validator-env.sh | 0 .../aztec/aztec-dashboard-all-in-one.json | 0 .../files/grafana_dashboards/default.yml | 0 .../templates/_helpers.tpl | 0 .../templates/anvil.deployment.yaml | 0 .../templates/anvil.service.yaml | 0 .../templates/boot-node.service.yaml | 0 .../templates/boot-node.stateful-set.yaml | 10 ++ .../deploy-contracts.config-map.yaml | 0 .../templates/deploy-l2-contracts.job.yaml | 0 .../templates/metrics.yaml | 0 .../templates/prover-node.service.yaml | 0 .../templates/prover-node.stateful-set.yaml | 0 .../templates/pxe.deployment.yaml | 0 .../templates/pxe.service.yaml | 0 .../templates/tests/run-tests.yaml | 0 .../templates/validator.service.yaml | 0 .../templates/validator.stateful-set.yaml | 0 .../{helm-chart => aztec-network}/values.yaml | 0 .../values/3-validators.yaml | 0 .../values/default.yaml | 0 spartan/metrics/.helmignore | 23 +++++ spartan/metrics/Chart.lock | 6 ++ spartan/metrics/Chart.yaml | 29 ++++++ .../opentelemetry-collector-0.104.0.tgz | Bin 0 -> 34837 bytes spartan/metrics/templates/elasticsearch.yaml | 72 ++++++++++++++ spartan/metrics/values.yaml | 93 ++++++++++++++++++ spartan/{iac => terraform}/main.tf | 0 yarn-project/end-to-end/Earthfile | 4 +- 32 files changed, 235 insertions(+), 2 deletions(-) rename spartan/{helm-chart => aztec-network}/.helmignore (100%) rename spartan/{helm-chart => aztec-network}/Chart.yaml (100%) rename spartan/{helm-chart => aztec-network}/files/config/config-prover-env.sh (100%) rename spartan/{helm-chart => aztec-network}/files/config/config-validator-env.sh (100%) rename spartan/{helm-chart => aztec-network}/files/grafana_dashboards/aztec/aztec-dashboard-all-in-one.json (100%) rename spartan/{helm-chart => aztec-network}/files/grafana_dashboards/default.yml (100%) rename spartan/{helm-chart => aztec-network}/templates/_helpers.tpl (100%) rename spartan/{helm-chart => aztec-network}/templates/anvil.deployment.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/anvil.service.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/boot-node.service.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/boot-node.stateful-set.yaml (93%) rename spartan/{helm-chart => aztec-network}/templates/deploy-contracts.config-map.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/deploy-l2-contracts.job.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/metrics.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/prover-node.service.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/prover-node.stateful-set.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/pxe.deployment.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/pxe.service.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/tests/run-tests.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/validator.service.yaml (100%) rename spartan/{helm-chart => aztec-network}/templates/validator.stateful-set.yaml (100%) rename spartan/{helm-chart => aztec-network}/values.yaml (100%) rename spartan/{helm-chart => aztec-network}/values/3-validators.yaml (100%) rename spartan/{helm-chart => aztec-network}/values/default.yaml (100%) create mode 100644 spartan/metrics/.helmignore create mode 100644 spartan/metrics/Chart.lock create mode 100644 spartan/metrics/Chart.yaml create mode 100644 spartan/metrics/charts/opentelemetry-collector-0.104.0.tgz create mode 100644 spartan/metrics/templates/elasticsearch.yaml create mode 100644 spartan/metrics/values.yaml rename spartan/{iac => terraform}/main.tf (100%) diff --git a/spartan/helm-chart/.helmignore b/spartan/aztec-network/.helmignore similarity index 100% rename from spartan/helm-chart/.helmignore rename to spartan/aztec-network/.helmignore diff --git a/spartan/helm-chart/Chart.yaml b/spartan/aztec-network/Chart.yaml similarity index 100% rename from spartan/helm-chart/Chart.yaml rename to spartan/aztec-network/Chart.yaml diff --git a/spartan/helm-chart/files/config/config-prover-env.sh b/spartan/aztec-network/files/config/config-prover-env.sh similarity index 100% rename from spartan/helm-chart/files/config/config-prover-env.sh rename to spartan/aztec-network/files/config/config-prover-env.sh diff --git a/spartan/helm-chart/files/config/config-validator-env.sh b/spartan/aztec-network/files/config/config-validator-env.sh similarity index 100% rename from spartan/helm-chart/files/config/config-validator-env.sh rename to spartan/aztec-network/files/config/config-validator-env.sh diff --git a/spartan/helm-chart/files/grafana_dashboards/aztec/aztec-dashboard-all-in-one.json b/spartan/aztec-network/files/grafana_dashboards/aztec/aztec-dashboard-all-in-one.json similarity index 100% rename from spartan/helm-chart/files/grafana_dashboards/aztec/aztec-dashboard-all-in-one.json rename to spartan/aztec-network/files/grafana_dashboards/aztec/aztec-dashboard-all-in-one.json diff --git a/spartan/helm-chart/files/grafana_dashboards/default.yml b/spartan/aztec-network/files/grafana_dashboards/default.yml similarity index 100% rename from spartan/helm-chart/files/grafana_dashboards/default.yml rename to spartan/aztec-network/files/grafana_dashboards/default.yml diff --git a/spartan/helm-chart/templates/_helpers.tpl b/spartan/aztec-network/templates/_helpers.tpl similarity index 100% rename from spartan/helm-chart/templates/_helpers.tpl rename to spartan/aztec-network/templates/_helpers.tpl diff --git a/spartan/helm-chart/templates/anvil.deployment.yaml b/spartan/aztec-network/templates/anvil.deployment.yaml similarity index 100% rename from spartan/helm-chart/templates/anvil.deployment.yaml rename to spartan/aztec-network/templates/anvil.deployment.yaml diff --git a/spartan/helm-chart/templates/anvil.service.yaml b/spartan/aztec-network/templates/anvil.service.yaml similarity index 100% rename from spartan/helm-chart/templates/anvil.service.yaml rename to spartan/aztec-network/templates/anvil.service.yaml diff --git a/spartan/helm-chart/templates/boot-node.service.yaml b/spartan/aztec-network/templates/boot-node.service.yaml similarity index 100% rename from spartan/helm-chart/templates/boot-node.service.yaml rename to spartan/aztec-network/templates/boot-node.service.yaml diff --git a/spartan/helm-chart/templates/boot-node.stateful-set.yaml b/spartan/aztec-network/templates/boot-node.stateful-set.yaml similarity index 93% rename from spartan/helm-chart/templates/boot-node.stateful-set.yaml rename to spartan/aztec-network/templates/boot-node.stateful-set.yaml index 3e5456c9d2c..79bff8d0dde 100644 --- a/spartan/helm-chart/templates/boot-node.stateful-set.yaml +++ b/spartan/aztec-network/templates/boot-node.stateful-set.yaml @@ -61,6 +61,16 @@ spec: "-c", "source /shared/contracts.env && env && node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js start --node --archiver --sequencer --pxe", ] + livenessProbe: + exec: + command: + - /bin/sh + - -c + - curl -fSs http://127.0.0.1:{{ .Values.bootNode.service.nodePort }}/status + initialDelaySeconds: 30 + periodSeconds: 5 + timeoutSeconds: 30 + failureThreshold: 3 volumeMounts: - name: shared-volume mountPath: /shared diff --git a/spartan/helm-chart/templates/deploy-contracts.config-map.yaml b/spartan/aztec-network/templates/deploy-contracts.config-map.yaml similarity index 100% rename from spartan/helm-chart/templates/deploy-contracts.config-map.yaml rename to spartan/aztec-network/templates/deploy-contracts.config-map.yaml diff --git a/spartan/helm-chart/templates/deploy-l2-contracts.job.yaml b/spartan/aztec-network/templates/deploy-l2-contracts.job.yaml similarity index 100% rename from spartan/helm-chart/templates/deploy-l2-contracts.job.yaml rename to spartan/aztec-network/templates/deploy-l2-contracts.job.yaml diff --git a/spartan/helm-chart/templates/metrics.yaml b/spartan/aztec-network/templates/metrics.yaml similarity index 100% rename from spartan/helm-chart/templates/metrics.yaml rename to spartan/aztec-network/templates/metrics.yaml diff --git a/spartan/helm-chart/templates/prover-node.service.yaml b/spartan/aztec-network/templates/prover-node.service.yaml similarity index 100% rename from spartan/helm-chart/templates/prover-node.service.yaml rename to spartan/aztec-network/templates/prover-node.service.yaml diff --git a/spartan/helm-chart/templates/prover-node.stateful-set.yaml b/spartan/aztec-network/templates/prover-node.stateful-set.yaml similarity index 100% rename from spartan/helm-chart/templates/prover-node.stateful-set.yaml rename to spartan/aztec-network/templates/prover-node.stateful-set.yaml diff --git a/spartan/helm-chart/templates/pxe.deployment.yaml b/spartan/aztec-network/templates/pxe.deployment.yaml similarity index 100% rename from spartan/helm-chart/templates/pxe.deployment.yaml rename to spartan/aztec-network/templates/pxe.deployment.yaml diff --git a/spartan/helm-chart/templates/pxe.service.yaml b/spartan/aztec-network/templates/pxe.service.yaml similarity index 100% rename from spartan/helm-chart/templates/pxe.service.yaml rename to spartan/aztec-network/templates/pxe.service.yaml diff --git a/spartan/helm-chart/templates/tests/run-tests.yaml b/spartan/aztec-network/templates/tests/run-tests.yaml similarity index 100% rename from spartan/helm-chart/templates/tests/run-tests.yaml rename to spartan/aztec-network/templates/tests/run-tests.yaml diff --git a/spartan/helm-chart/templates/validator.service.yaml b/spartan/aztec-network/templates/validator.service.yaml similarity index 100% rename from spartan/helm-chart/templates/validator.service.yaml rename to spartan/aztec-network/templates/validator.service.yaml diff --git a/spartan/helm-chart/templates/validator.stateful-set.yaml b/spartan/aztec-network/templates/validator.stateful-set.yaml similarity index 100% rename from spartan/helm-chart/templates/validator.stateful-set.yaml rename to spartan/aztec-network/templates/validator.stateful-set.yaml diff --git a/spartan/helm-chart/values.yaml b/spartan/aztec-network/values.yaml similarity index 100% rename from spartan/helm-chart/values.yaml rename to spartan/aztec-network/values.yaml diff --git a/spartan/helm-chart/values/3-validators.yaml b/spartan/aztec-network/values/3-validators.yaml similarity index 100% rename from spartan/helm-chart/values/3-validators.yaml rename to spartan/aztec-network/values/3-validators.yaml diff --git a/spartan/helm-chart/values/default.yaml b/spartan/aztec-network/values/default.yaml similarity index 100% rename from spartan/helm-chart/values/default.yaml rename to spartan/aztec-network/values/default.yaml diff --git a/spartan/metrics/.helmignore b/spartan/metrics/.helmignore new file mode 100644 index 00000000000..0e8a0eb36f4 --- /dev/null +++ b/spartan/metrics/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/spartan/metrics/Chart.lock b/spartan/metrics/Chart.lock new file mode 100644 index 00000000000..57771d95b8c --- /dev/null +++ b/spartan/metrics/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: opentelemetry-collector + repository: https://open-telemetry.github.io/opentelemetry-helm-charts + version: 0.104.0 +digest: sha256:46e9235115f0e0243ca03286d9b171ba2d04da7817843a55d4a926eb45210273 +generated: "2024-09-06T17:03:51.114471301-04:00" diff --git a/spartan/metrics/Chart.yaml b/spartan/metrics/Chart.yaml new file mode 100644 index 00000000000..e530685375d --- /dev/null +++ b/spartan/metrics/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +name: metrics +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" + +dependencies: + - name: opentelemetry-collector + version: 0.104.0 + repository: https://open-telemetry.github.io/opentelemetry-helm-charts diff --git a/spartan/metrics/charts/opentelemetry-collector-0.104.0.tgz b/spartan/metrics/charts/opentelemetry-collector-0.104.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..00fefbbd2b9273ed9983825f7e2d4b0127722f1a GIT binary patch literal 34837 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 Rk}((z0MZ6VC}z6`<{!O&uH*m! literal 0 HcmV?d00001 diff --git a/spartan/metrics/templates/elasticsearch.yaml b/spartan/metrics/templates/elasticsearch.yaml new file mode 100644 index 00000000000..ef3bcb72533 --- /dev/null +++ b/spartan/metrics/templates/elasticsearch.yaml @@ -0,0 +1,72 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: elasticsearch +spec: + replicas: 1 + selector: + matchLabels: + app: elasticsearch + template: + metadata: + labels: + app: elasticsearch + spec: + containers: + - name: elasticsearch + image: docker.elastic.co/elasticsearch/elasticsearch:sha256-ca844065f663d0a91fe82b4d540ad1e6f4c4ddc58b354cd1724bf19e56f01409 + env: + - name: discovery.type + value: single-node + - name: ES_JAVA_OPTS + value: "-Xms512m -Xmx512m" + ports: + - containerPort: 9200 + - containerPort: 9300 +--- +apiVersion: v1 +kind: Service +metadata: + name: elasticsearch +spec: + selector: + app: elasticsearch + ports: + - port: 9200 + targetPort: 9200 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kibana +spec: + replicas: 1 + selector: + matchLabels: + app: kibana + template: + metadata: + labels: + app: kibana + spec: + containers: + - name: kibana + image: docker.elastic.co/kibana/kibana:sha256-ff5f6b9a49f410658b74b337b102c302bbeb52b470efe1f0e3af3c7526fbe0e7 + env: + - name: ELASTICSEARCH_HOSTS + value: http://elasticsearch:9200 + ports: + - containerPort: 5601 +--- +apiVersion: v1 +kind: Service +metadata: + name: kibana +spec: + selector: + app: kibana + ports: + - port: 5601 + targetPort: 5601 + type: NodePort diff --git a/spartan/metrics/values.yaml b/spartan/metrics/values.yaml new file mode 100644 index 00000000000..bb79b6d1aa7 --- /dev/null +++ b/spartan/metrics/values.yaml @@ -0,0 +1,93 @@ +opentelemetry-collector: + mode: daemonset + + image: + repository: "otel/opentelemetry-collector-k8s" + + command: + name: "otelcol-k8s" + + presets: + logsCollection: + enabled: true + includeCollectorLogs: true + kubernetesAttributes: + enabled: true + config: + exporters: + debug: {} + extensions: + # The health_check extension is mandatory for this chart. + # Without the health_check extension the collector will fail the readiness and liveliness probes. + # The health_check extension can be modified, but should never be removed. + health_check: + endpoint: ${env:MY_POD_IP}:13133 + processors: + batch: {} + # Default memory limiter configuration for the collector based on k8s resource limits. + memory_limiter: + # check_interval is the time between measurements of memory usage. + check_interval: 5s + # By default limit_mib is set to 80% of ".Values.resources.limits.memory" + limit_percentage: 80 + # By default spike_limit_mib is set to 25% of ".Values.resources.limits.memory" + spike_limit_percentage: 25 + receivers: + jaeger: + protocols: + grpc: + endpoint: ${env:MY_POD_IP}:14250 + thrift_http: + endpoint: ${env:MY_POD_IP}:14268 + thrift_compact: + endpoint: ${env:MY_POD_IP}:6831 + otlp: + protocols: + grpc: + endpoint: ${env:MY_POD_IP}:4317 + http: + endpoint: ${env:MY_POD_IP}:4318 + prometheus: + config: + scrape_configs: + - job_name: opentelemetry-collector + scrape_interval: 10s + static_configs: + - targets: + - ${env:MY_POD_IP}:8888 + zipkin: + endpoint: ${env:MY_POD_IP}:9411 + service: + telemetry: + metrics: + address: ${env:MY_POD_IP}:8888 + extensions: + - health_check + pipelines: + logs: + exporters: + - debug + processors: + - memory_limiter + - batch + receivers: + - otlp + metrics: + exporters: + - debug + processors: + - memory_limiter + - batch + receivers: + - otlp + - prometheus + traces: + exporters: + - debug + processors: + - memory_limiter + - batch + receivers: + - otlp + - jaeger + - zipkin diff --git a/spartan/iac/main.tf b/spartan/terraform/main.tf similarity index 100% rename from spartan/iac/main.tf rename to spartan/terraform/main.tf diff --git a/yarn-project/end-to-end/Earthfile b/yarn-project/end-to-end/Earthfile index 73a71fe6a8a..8e8c05c9377 100644 --- a/yarn-project/end-to-end/Earthfile +++ b/yarn-project/end-to-end/Earthfile @@ -92,10 +92,10 @@ NETWORK_TEST: RUN kubectl delete namespace $namespace --ignore-not-found=true --wait=true --now --timeout=10m END - RUN helm install spartan ../../spartan/helm-chart/ \ + RUN helm install spartan ../../spartan/aztec-network/ \ --namespace $namespace \ --create-namespace \ - --values ../../spartan/helm-chart/values/$values_file \ + --values ../../spartan/aztec-network/values/$values_file \ --set images.test.image="aztecprotocol/end-to-end:$AZTEC_DOCKER_TAG" \ --set images.aztec.image="aztecprotocol/aztec:$AZTEC_DOCKER_TAG" \ --set test="$test" \ From 8c0cb2950e68e59171ee92da4e3aed480d9a82c6 Mon Sep 17 00:00:00 2001 From: Mitch Date: Fri, 6 Sep 2024 20:37:56 -0400 Subject: [PATCH 4/8] logs flowing to eck stack --- spartan/.gitignore | 1 + .../templates/boot-node.stateful-set.yaml | 2 + .../templates/prover-node.stateful-set.yaml | 2 + .../templates/pxe.deployment.yaml | 2 + .../templates/validator.stateful-set.yaml | 2 + spartan/metrics/Chart.lock | 7 +- spartan/metrics/Chart.yaml | 3 + .../opentelemetry-collector-0.104.0.tgz | Bin 34837 -> 0 bytes spartan/metrics/templates/elasticsearch.yaml | 72 ----------------- spartan/metrics/values.yaml | 74 +++++------------- spartan/scripts/install_eck_operator.sh | 8 ++ 11 files changed, 45 insertions(+), 128 deletions(-) create mode 100644 spartan/.gitignore delete mode 100644 spartan/metrics/charts/opentelemetry-collector-0.104.0.tgz delete mode 100644 spartan/metrics/templates/elasticsearch.yaml create mode 100755 spartan/scripts/install_eck_operator.sh diff --git a/spartan/.gitignore b/spartan/.gitignore new file mode 100644 index 00000000000..aa1ec1ea061 --- /dev/null +++ b/spartan/.gitignore @@ -0,0 +1 @@ +*.tgz diff --git a/spartan/aztec-network/templates/boot-node.stateful-set.yaml b/spartan/aztec-network/templates/boot-node.stateful-set.yaml index 79bff8d0dde..d40c9969f2b 100644 --- a/spartan/aztec-network/templates/boot-node.stateful-set.yaml +++ b/spartan/aztec-network/templates/boot-node.stateful-set.yaml @@ -89,6 +89,8 @@ spec: value: "{{ .Values.bootNode.service.nodePort }}" - name: LOG_LEVEL value: "{{ .Values.bootNode.logLevel }}" + - name: LOG_JSON + value: "1" - name: DEBUG value: "{{ .Values.bootNode.debug }}" - name: ETHEREUM_HOST diff --git a/spartan/aztec-network/templates/prover-node.stateful-set.yaml b/spartan/aztec-network/templates/prover-node.stateful-set.yaml index a1804ac40d9..cee694e36b2 100644 --- a/spartan/aztec-network/templates/prover-node.stateful-set.yaml +++ b/spartan/aztec-network/templates/prover-node.stateful-set.yaml @@ -59,6 +59,8 @@ spec: value: "{{ .Values.proverNode.service.nodePort }}" - name: LOG_LEVEL value: "{{ .Values.proverNode.logLevel }}" + - name: LOG_JSON + value: "1" - name: DEBUG value: "{{ .Values.proverNode.debug }}" - name: ETHEREUM_HOST diff --git a/spartan/aztec-network/templates/pxe.deployment.yaml b/spartan/aztec-network/templates/pxe.deployment.yaml index fefe94987c4..d4a2aa1af6d 100644 --- a/spartan/aztec-network/templates/pxe.deployment.yaml +++ b/spartan/aztec-network/templates/pxe.deployment.yaml @@ -29,6 +29,8 @@ spec: value: {{ include "aztec-network.ethereumHost" . | quote }} - name: AZTEC_NODE_URL value: {{ include "aztec-network.bootNodeUrl" . | quote }} + - name: LOG_JSON + value: "1" ports: - name: http containerPort: {{ .Values.pxe.service.port }} diff --git a/spartan/aztec-network/templates/validator.stateful-set.yaml b/spartan/aztec-network/templates/validator.stateful-set.yaml index fec535503c3..864b42daae9 100644 --- a/spartan/aztec-network/templates/validator.stateful-set.yaml +++ b/spartan/aztec-network/templates/validator.stateful-set.yaml @@ -59,6 +59,8 @@ spec: value: "{{ .Values.validator.service.nodePort }}" - name: LOG_LEVEL value: "{{ .Values.validator.logLevel }}" + - name: LOG_JSON + value: "1" - name: DEBUG value: "{{ .Values.validator.debug }}" - name: ETHEREUM_HOST diff --git a/spartan/metrics/Chart.lock b/spartan/metrics/Chart.lock index 57771d95b8c..85b5ec4e110 100644 --- a/spartan/metrics/Chart.lock +++ b/spartan/metrics/Chart.lock @@ -2,5 +2,8 @@ dependencies: - name: opentelemetry-collector repository: https://open-telemetry.github.io/opentelemetry-helm-charts version: 0.104.0 -digest: sha256:46e9235115f0e0243ca03286d9b171ba2d04da7817843a55d4a926eb45210273 -generated: "2024-09-06T17:03:51.114471301-04:00" +- name: eck-stack + repository: https://helm.elastic.co + version: 0.12.1 +digest: sha256:e95083de14387953eb4093eb2c6b98cf889e532cd097b21b15b1896cfa117e7c +generated: "2024-09-06T19:31:29.086654335-04:00" diff --git a/spartan/metrics/Chart.yaml b/spartan/metrics/Chart.yaml index e530685375d..04a896c0fce 100644 --- a/spartan/metrics/Chart.yaml +++ b/spartan/metrics/Chart.yaml @@ -27,3 +27,6 @@ dependencies: - name: opentelemetry-collector version: 0.104.0 repository: https://open-telemetry.github.io/opentelemetry-helm-charts + - name: eck-stack + version: 0.12.1 + repository: https://helm.elastic.co diff --git a/spartan/metrics/charts/opentelemetry-collector-0.104.0.tgz b/spartan/metrics/charts/opentelemetry-collector-0.104.0.tgz deleted file mode 100644 index 00fefbbd2b9273ed9983825f7e2d4b0127722f1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34837 zcmV)SK(fCdiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMYca~rp^IC%e_Pk|qmdu{oOLsF7uhkKG*MfQoc*AK0vXl%sBd=d_;IkBoV=s&Bzcz*DLW`NLeqSk%HU$oz5n` zgiV+zf9k4t-4tJjSvm=3n5GiblyET&x+uk}$#_O3pX1N&#c!Cil#R#Vzi_Wk=Lz8o z_gqc`{i)%m}(yZbo*AL7|SugDnZi9~wDVfMB# zMHpBpDhJlwl!AjA$wu znzNiENoHAsB@tl&Gw;JC;he@~h&r8MoF_@`Ww3#M#R-iqs;ZezjLD3pg2>Jm>ck{V z*nCD(^$Vvl>IjJ?8Rv;A5C$_=fI7)YM8|Vt5wDG4Nha#_YoE}LJ>>HbdqzJt%!|L#AX>wNh$@BQ!IlGgcHFKC%@;E z6Lj%Xpc#wl*i3Ms;T7W-C}NzGNG5Yd>hM=RNi}#B;nc?(0L*(hhF=(EoCu4t0Od*{IvlIvbf`mVoTyIXbRKLVK_cA+^`;TV766EF znlhUYtc8V)Q_N+Kcz=JPPnxQSta&;~lN1%*M(>O=qnKTyIZB81ZWajeU! z36ro1;v^#Ul0b3wUKK?d%}7F10##HWu&w5>K$k4ZXKEUxvH2U#Se{DL&`(52J&0FS zP8B;4^aFC!MHf0Dq+RvKEE2s7r^$PTb}0C_w_*Cxb^TBhBqkEmL?D)$X`{cXMpgfe z-Jo<F16QQUG!^0VqTSzdN zw1`TWa?r5)+5}lh#>qi}Q@IDHQ-WsrGo9r#G@2{)1^t7lnPP~>W+R${a3x7>as7}+ znxCOC`5X~qcq5@RDz^|$5=-$I5oI(GVS#G#g|29ls7dZxP)syVaxo>Qof-aoY!P_N zCMWa{GDL&^_HMtwGS>q|6g$zV%Khq-`BIw!_Wd_B2~>Bw2Je+;f~xdR*J+ssH8K}= zH9F!<5kXU2NqO(vj7S_~i7Q0Ecqy<{He{{}WhDSfqNT2(xmZMWo*TV>kmN#=W2RL9 zLz25F&@DRDEjqM>@J01~SG!dZZJ>WmNov0s)nprjc|<--j)8&+9+5=bP&h?c2o_PS ztfP#@mY52{Oz9JAOQ50)p(hvs))RrqXBfiDsw z!|JrruazlzJ7M)z%p2R2mBo~)w5FtL9GU__L@tSw(!PLVqu*4?)vO`|SJVNc(HzBk zWwVgPZoz;UN8V!LK17x7+Ioc7RbNA&ZlEMIqj7ZXk<$)Fq`!3&a!HaFHGT0?oSAYD z%J~mDES3(d4vQ(jXg&mb@$e33dWoRdn#v5jni5!rVC0H;E6#`$5VcPw&xyyvo2ps( zHbm-E1t?At`AmgW#_)jytJmFN4e6B}$bJ?FRyr3&-~DoOYAx={>@BZdFDX`XlFUJl z$LI+s37$Vuqg1X25?(Fngv1<%&0_c-ylkCLr4O3Q36}JdpbX0?uxc(OoB4e*P6O?3 z(B23Ju1R$A=EE;lrE#v45I*5#|fZry6hT;1%}9H zo^I1jY5RAC<%;^io^3VD*m5MoJ5G<4)0j z7!qsuh?%M>QF3Br+#Pnw;$MV z#|-60SVmJrRfVH<(9Ot9kqZ`iq&hLjwHY|VY8tQ<+!xMHgW9J18sM1$XffWIcsWg`}tZ8`hfgq zx1R^dsR}cizhN>dh?{XHS;P`yUm!H$SycR5%rU#$&-<>ZoN_vrXG#&SUVrapwZ77d zIFc)Z*n7D%fRaom+1>PNcW3azm0Y7YyE_BjnT)fU(yF;@zmQmFz#@(_a;9GkAAT48 z#ztq0cYcuf7)S+I5Bj29K*LFpFLfXPpxFgYSCA^-?+(-e zsbvj~h_2u|W$Vv;+eJM%jyVyc0iMI4D&Q5qzQof*VciF|jI!H{W-9u_f&o3^-c;qG zEmam*rB5I--J8k`w1pJMw)OvOK}^3W7}~s63uE%tqN_z*>6K8}W>~?7hIX#so^K(MM^j}oVkEQy8v(H{DdEZ#_Fmfwv8B5JDjIgl zsnB++f)Z>Lcm^B62KptH#*R^xK%;!3%8%)1Wru*R1Ri1aGUM!$#s*M|a3Tp$wH56V zt+1~Q+C_8d5RlPCh}djK(paw-^uCE}48VaUni#jc?TdDL!=_YV{7niRnPqamh0ZNb zL>u1c&i!Mzm_Q5r#>*2?+h&r$I`2Q&A#xiwVBj5|p!Xk6(Yx2jKfivZmy#Mli1yQY zg*6<>lxc4V)geVEDdT1V5o|PIug!)K{hQ@_;bh?HZB2HSF0lB64RlOqG>z3VTCreZ z-d63;r)uR3azGKABrq6Q+SasDCh&})ah}3n3Qnk;Zz}xEZd|NeJScV>-KJKoR+nZQ ztLS?A8;PXb6VuSIFl>F!VY^kCnU-QMQ^7Un=qCqzik%)}^V zX&0u2MtMuOQ;dMZP>+qN{FIXk=5eByE^G`4LCsCoqAmlC0-U2fNlr+_m3@Ieep2GM zEnbIwCQ&ZcYBw;XR6~{)Yjg0%?(>O(WbBFkC}Mdk+r1j59KyO_-M7)?$?%-Lb~D4c zD=Oduz^`mKxhhC#-U}^Hf?I+}?Lh=wU|6{t53B)EfhHs+9K11BgsPdQ z!xEf3z^7SY97D$}Aq(6-MWIIGY@ic1BW`K}^Gi-A6Ji#4s-y`caL^D};GjSLixEv@ znoeBDbw^lg2&MSiv{Th8DeJN<^v0@iHntCz*EQ{D@d6TPYW5m6@*tsYA3>~{fhcz= zTyemCqP7k8+5>x69Y}qL*FGS_#>OLx1&Udet93Mq(Ufq4ideY9N9p{UoQw%4X+(NB zQpQ~u=W?3Dzkl@j2uHm;Lfj55j$^8Ii^dq_s`>-Of@-Uaa7KUTEYD0lgtGshJTZT| zm9+OQW3hNr{7hL)-0w@mM}FA}kzUb+3jgPoGFP7jg-=#7z)za#truz~b~SZOl{=uG zH}je}cnJ?1bUaqRH8bBwzY58hvG{~UIj3@dz*0#*OX#R*co(SQJ|S8S!5hgE!Yz3| zehTn-Oj9c7=3~YZHkqGfoZ$F?r9yJ7BPq0k+fNd9rMD|H79$Z&Nt`Eyql{C=siZ>N z@aE_IAi+X7A9Mg}?sa;p;kjS`1}JY~&rpL)exMYHmYlF4%y5(<7#rCV&c7q$P0x1=M^hd_Hc! z!{~5SY_lp5L*$$~Mi*D!PMMIESJsI%M5hNwhGQ*CL$uSk<#3iAxuO%EMFz2M;W}Cc zyO)jFy{u#RvJpGI=Ixf8XG@!P&a+ap?rqVmdsQ_1%PX&0?YdjB)xzsnYPNV?v|GGu z>2KlITcug!tgJR`UYD9R@2buEZm*>+8rN5)LHD+3&%LTPSMm#)_$<52X=X-Dg^r}~ zHki>Hb_F{EYPn)pDjHq0>Bgl2NmImltT$2Zdgw%>`;Mh*v4Wn8((lmpdlNB^j#%u9 zW$tfRBy0;}sZh!}^-7d-Z_8u}${{3M-U0|@kzKw2{Ndf}cW)2h9iAeRUZP9PJzu_F z_qoMqi-R595lYRq6@W!(OvVtiCLLBv^TmvS7h?+g$+|V(9RB>~?Y|4pMrma9$_#ec zl34<4$O?Y8G3!U5bWCOT3wHMLNW$f&0(2yGE5EcO$M1yKre zfn6@KxDY+ldQa~)(?3WTV0FhdA>A?KU1j<903!p{v!ZD>M4dsn9qxp?9b@CFlF$`v z5i7H|Gn@q9NU%fv;8MroV%*Q_|7jmog>t9q(-)M4dq4z8$TXu6%{|w?( zSpSILz&_9$@Cv&1ryU#LlJ*CB?NR|iLIuTl2yGyiCUY;y!;9{iv6uv$z)_Y1@GPLg zN;NL2pe%hug=BpGR!xN=8uWvpYHJ4@=q(kn;?i+$g2p7m-12vLZ^qXFb4QZ2Az6JJ z=v9oiq9qa1PG#$l*>LXkC^J7Wp9ud$Z$#6cNC?UNmkLGQ7+~q_IU`$E^Kp` zzLDrbso@1;MHSN#4$z8EUuCp=(RLyuk=Q~coP;oEBbLo|D27^f@VSXk(T*r9JrX)5 z(L74jgk~4_GB|2Us80gGZgm}VINt(jtM?Qq^bdu%n#5u*B$=U%@EH}tt|^uL`EdI7 z$aAkj#Q6E3-|r93VXcJ)(auax%t|dITu>p^Vji@Qf?^_=wOc>VBTcWOITVwWk{A)r zO_Xax+pZ&FpgK_F!^+DxHeAFr_rRjJW5bQ2sOnyKEOhAwov8Mqi^R0}`$;!?;{A%I z>?%dwV+2DwEY1}u`GY5<$7J*bZ8(z-0+=TBlB9~SGsO(W{%NRK>CDs&-HCy7^j}b_ zyl(sW`BUh+d#+Jxq?PS|+ws8|OYC9jyB-YNfxLwkVZoXO(S4dX^!_0_Z**NDBtY{} zBErDEd&Ag;H8m zu!-pKkxVhjnDLnnO&=NGZALf+w~~R;U)Uq90UQX3RuYKiCSp|mWVx(h^p2)*_9kMf zP+Evy5{Mv!NLnjh4LoMliLxJ*^`puutp%-5@ud>gB99_MVoM7H>U7G9n6f0c&AzhU z7oQF~HWOBlTB#_ZpDHak;W#4WTxqmC)7zILho|YDDNI@VvnqYmKs&{UKNI6L$n?6~ zM4%yMd?C%(V+fS>Xja9Ep#Z5L6M?I|Xi!IWUgivIr+dWKpYtvioO68U=e0pr<>~wP<%0 zmAWI-&)x=XlW@hKT{$J)D4`^kUF{F)(rnX2gD>iH(6F!BO72#=LJ(rT4WPi2CZ=1H z(kDwAvID3OPq|haqKS+UT}%?1P9O#`XguT6v<+-(cw0K@gr=Y28+cxdjYRcxSOn&T zCN4gV%$WcyD?CpNMB*9oQM}W|PGPPcaWbZ#%OCx1gAF7T4+jCE85+^TE|-aL5K2g! zbyXwE_LPp@n>Cam0(G_T#4-yV+i%uMY-1ekcw79g6hbjZpWHkcJ37>dJYAwaO+ zVm;?S!XY&tK|YtP#wQJ&vVd2Lje?t%i2)~ZrnhP|*rS0qWorfF;{zc%5^W}~HRC}O_4(0wn+`nk|7@3EM7 z)>dI#?2OppCC}?@V-XU91sTG@x^59ny3#$w5{La&%dO&cngkj zoJ%Gm4AiS)0P3BJQra730+o{91RjJ&)jFf;v39_l^#f#na4*#IWJHubZo)N?Il^#o z^vf@jCiD-W_fhrq&4wxV4mP6NO9q@J3Cn>{>Q9K_7+BSP7!zz!Z8$ytvS6@BE1=d<=nCjR#Jb2*(nZ4U;|aSVjvz z?GrpmFrA&+Oih}K{(0O0H5N3TRf-3vcmn6d+{V%o<~T`6(y@mzC1;6H46S6wlwF~t zUk`+{U`9Ig(uryGgh;aqoDj7>M{XV=n)*kd2jTY4e=Di#yqWUX0@Y)pUMP0dXtiye zD`tA7n;N2HA~8+f`;!PK-s`|@{}m9M2B|$B?Y&>UZGmu5N`mxc%-QS-iV~a)=glp_ zsjg&AvK$I2VuTWZ5=m{4gUX`?F$8I~0gXX(MqOV;+|~fu5*}p*3W6ry&Y}x+ta@1eK>_HZ19pg)x+V8j+0l z^gd?S?QPrr+^+d>IZ%ckL`4}B)rE%KmLlFq@_qAC38`mK+X!YK)}Qq)xP z%v~r~ij?zPanll}E)wQ_bR$ciP-1(^>~d7xYZ8wIpv<+6-$3h$ct4YOWfeG>h3^9NLqnLo#sNMaXhxY20lnq_(=XiL3S zEb1?zYRulw@KEH~$}XaZzBGqnkF|7;q6mbs`4m>7J^8Ci-#~QKMUr`RS|ocG5w}X+ zemLm&ws&or(#U#)JJ{aY_2JY)&$J}+Hs=-pPn88=&NmW)aKxF=SsNVk0TePxvfkUb zRu%u%X*a)`XG#875lzVqhrbDy-n@+^`CnhW=vVWLgU|S+r~lmOY(epuj74XNuE7%S&{TflCsHk3+)IQyIGukOcZTSrI~aWJ z9TD!xc}7%&LRWO3zHBWnPg6-IgnJdtU!MZ|3qZIEI_r|gTvD09OP%LIzbrKW5m(lQ zq(t=&1O*hx{MV+_#zgiz?B&T;P5dHs6jHG!)p0)`nrB?)TyDpb!S!RrSVC~BJ8r1d znIvq46CaC8w@an{jJgXjw?)dwQy}2io*nVlStel@2;K&?{qePURI~f8f{We&|2@YE zq+>xi%b?8_o1C$7GnKLq21)aoV%i0Hg-h<0E!63Jsu8)A6L^(oE4_a25x&SwyeJiM zSnjSl%CmqmT+_?g-@vO)0eD|d=34sJ-sH;7E^4}E7P?Oriq?-}mb2xUqnM?9y(NU( z=b{rt<>H;D47PWVDOD@$tMpDVu4b#f5w?)2&ric!oN@*D@k)7lZ`qTE?6qrkM(WJG zMGjuoEl9Y#0JEBELY{gm|Lx)1@zTKleI`&T_3yfaxs+t(l$3uTs+oS>FX5`0Z@+!= z)w3T%u&ZQ^`Dt${S{m~0-nb`i37Jj5OjB?GM=fr(SN~2s;JKq8su!ML`#u?5=S=Sn#p|+)GMbp{rk|)o?*XRxf=NYx0bg{>$-~V-DXzny{{_$m(pO(q_Sl)w3EQ+ z5I>9S%J}*DX``k2X`8WH;3w$#saKaEbzDs`3#l#rtgc*g^2N58jzC!v ze>gt00R2PA5|sER|$d8LuYBt7{WD zkhI7_wlu-lJ+ocfpb1tJ+9ttRTjeqZTd26Ox#ilroYw5#-DS;seI><?Gh1p{|QTBRz*^3^jSgQw-1b4^hRTP()^Il4+2RG^43BII9^>u3l@fQvN zT5h?o!Qk~2SF7&2h?`aO^JJ}B$4jMke>%zL=UN@9mK0w1hhi<+*MdEmQpHM+hC9K~ z7eCEY3Q|vc)=k@dYMuhCslSr3=P^5g{M2mbloAE}@1}*z40nG_TS`86&&`w*iZ!V7G>4f_VwRFPvfQz3IqD(-?ti-Ni&0f|4l#eTs7pB4@s z$);pRI8M4I56NwL!CVh>H^ym2I}!0n@q4CtA$=QO$Mt*G-y77BBr(^#ZrVvM$`4${Ip=7gneywO_TKmxaEmO5@=!FHijadCy(S z_XS&It_>GK<7bucY@tp|mU;EbWSEEO8kUlV6H_i<{HnzC6UH~yDKTVGsh%@_<;u<5 z*h{v3!Ha(H!nS!2VYP4wQ)p2owsZ4w#0_qWy>qZAI0 zZW38h&Te^I2!0OCy9?J?buaRk!6}XT6>l@TdORbXcyqSeXk(tsdug;$dYNn%U-cxb z<|w=glirdwASub+F?6F>U=5$ZVvj((KVZoswzen+qoc*?u*^ZT&^@!vKe8r0R-ua5 zqt>r0d5s#K2M+dWT_Y@l-wes0)~`R~2sDFEg{l5JoMj251OtXP#{{Ylfu+c{yHC(c zE)>-0L2GHS?0wYVLgvrtrbxM*{n8X?Eu=>JGG0{rgt;Jn*`fZ8Z4y5 zN{FoGE^8L(^=!A_%pkS|V%}i*mZ-)XLR}nlxjMG-Qz`@!uH;TCI`WHoQxIB zjUJ>5?fDr(7a9oVs~2tuda3ZXcRJi?x8j4j6+qeP$Hbf%RezUg{i#I?SBkC5Ar9k; zL@M3x@K;T6ea*$g>tO$GjJsm)8=uSau`RW>>|oDdVZ?c9OmD$6P4|C1JQp-vHL~(P zTj2lSQm1s8$HK6RMz8LoCFu=WZz=Ot{k?a0^uBuM#Ugmk%hsyZYA=nqIc)Vkr$y2# zeLttWJfW1`D_rZQgC*C6@EMS3;gz#@vq(4aC-)*UtU<;w}G=PnHL$s;2xVhy4~Ww zhx_4%Wbt6svIH4goBJ(FccpEucKyz>+bbTPv`aYdt|(v86jnpzg8cm9-RpO658oZ0 zt{l|YcrC^9+AghqNwGs#^H0H-o8M>AcK?G-i6?sRKb*ck3FT*b<2DxG|ImNl@9$Rc ze|Y|4=kflBhj^~9yNHe^;Q|#7t{MIXT-;^Y?F5EL9dZUDmdNWMZo_W#6sJ|Tje7yha z@cqx>Os8X{sgOL6OnzB|JV|5qS75q}(-=KfeSS)Qcm0Oz6urFvo13j=it7N{3;E{t z=4LYyRmpFUa9&qk^sou;HPrAv>&RZy|89i>bx4H;E?|0gD^36~qu7!QH8l9@1k5q)HZd zheG35R8El})jULlPN|;;>xo29X<882ud|5;=%%RqaL@$2863$eP7zCsp6FzzwlIR6 zd2q{LN~#P~8lm1ZbcquhV@cpv; zKTC?Vvf7WNYJB|H{_*?6_dkE~GYYG<0y0;f+N{26M%p~9dM%*}NPIyM8IMUM! z+IszipY*qps0aE6R>fT{wO}&Wnle|BFAz32!14&o>H1hgt(#!!k7RKtOKAw-dx_|E z3Kax%PAB(3SA-kkf51{fW5VH%e|@E8qV$je+J)+;ld}oj)NG5z)$)W)qnv>hl}>{f9vjB<%|Ejv(C zd`Zl-B`Fd)Bsh+d(Cga*3?k_zy2NTgl`b?B9mml16P8>OeS2%h*(f11NOo+9>o7Nn z8@xf+P=QBqe{>0Fk5+%R4f^=}buf#e`%BESuX-SWLfzt7udK8cBEY zpsV>OSi$cIpAehKo}i}%Ft>2}&h&5igEN^|8Zh1dpWr<9iP^AbDqrSST{Bq(eo!lr zB?y26_iYKB#ph{-4uGCBU`->N9>SXq!{30scZ=4oF@ICQx^J}0H(A{p^ZzM}s)Xx^#lrP)d%5UfJqpH0!T2Z`|9*n8 zdY#%Gc0vPul zpPQSTn=6oYTF28W3ZGtfO<=olrm$DW{dX1rufsDm_>~ZQinC0Sa%rv5RnjLmTxb78 zc}joZL{%1QS*)xyU=1`-W93j71_*gb3}H){GbYb6ET==%Qy<3yUPn%`oPo#f5+_46 z=;c;-dJa3<@z9lFWwQZaMi3!+i#~x}E8;{9$P~ zz5NS9UDS)oW$#)2b;eoL^j^$G(`%lmy^9^ub9vF@rc(9};+RDjgfA*#lu;uFDb6bI zXIMtlGda)55OFdgpR)!EjRlmb(4hIPY6$0&nIZOHk7zoc$+H<1QT;`yIL+{8%A{HCeU{{$N0Y!Q+CDDbp|86q`MVyBvvV*gXEal2=gzy4YpzCM$=89VXy+zzz%)n+o zXxMmJk;MmKpAQS8mr0UDEb;L#i2%b78i3*MA^KrcIZ@H{=E@sFxU6?7{NTwgDDSUMa!;0icf zrOr4{5;$BBRi2$aTdAdlT@fB(LCzowssKej_Kc-xCgW|f zkTI?oeZ$)ttk57dbkmxBOU&Gaqv`n>l+){Fhe7F^>asbj10PvNIF_tfEpMOuGc!!>1W1tLXHiP7PgOwUuU4-P4L!v0d+abgH)geGZT{zi%-{&hB4xnCea6 z-$;QY;m!w2Lw%5O(oNlFm<$Ql9i>{sHy)(BTDUC|<^`H&;a?y+Ea<-=7}QdAOcUoW zKqzHOe{wcEBkASYCFVm^TDt``g`8m_0 zt5f}4?6Eh0_f8hH0I&nt{5j$*{f&*9Kem2Qqu%^Qk*f7WPUFV++K!a8sJ7O|s;2aQ zk{sD|{+8Def|N4Cr@F)wW9xnQ-N5soUXb}2xa)`LY4~i@`=ZA;W3h*v$I!RH*1NKx zfaV?CzBjz9(IQAki^wSf`Ha{Y4jn_th+Q_X92eqUAX~R5^;zbIz>rXXG37WMHTmv> z%(rwMRpq-<5oH^y7yhnp*UVaFNnen;CaNl=UqNvXJ^fwhcR4DTD&47T;F$Yfy;Am7 zNr~xC-UYGxtM|f#P%Bnf;JTo_0aur@zdT5Ofp%SU0|v-gy!zm0EdFW+zBGn+Gqzw% zg;eZMNGeT1d&#jbXn%Q-$_3UOo3$5n<;aS!&(T>8D*5_cofj{KJ{f+GPWHC3s_xGi zM6@O-{eWFhV0r>j3a0{#$q;p}u#BdKzJ;CNA?oPDq0+sS6`$?K^i{Em=&6z}>b!dW z_VwxOS0yj}Umd>w_}ubY;rz#xBpKo2<_AC)pZ^%Vcs|&zp8wc=@p%5@K^}+{e*HO9 zYE9{WB~O&@hlD#*%w@QGII#8^cZUM+2|zhlZD`W5 zBrGKbScl_6n8l*K0un2;Wld;)CW8hP?Y9L`OEf*ur)seqjB%bMbM$+T6FR0OR(3Lw zIt>0rG;ct8sW?Q9sX!wVVK`RLW&{<6kLF%D?J5xF=CCb^bt)k$(9_WzIQ!N66IGU` z6C^ScZHB?&7;&OcxdRYmAqsOQ9Ntmsk~QT*;VBRX&Kf3u*IUH5{ zzRLVD+hbtAKwrQNUvYvKI6A6mAmOnlSy&tl?^a%}iCo5MD#xhvpQ8JpqEmsT8(m#o zELiPWCiF&ENkC zOuyG2pDMw+jlFT};FWfl4U%;*G*#*+B4v{JGreg-Rc#3CJHnC67LtoKlxR6v=zW{e zEEn_gX!uHh`O4JWI^S%Ao%$5;M3-&FrFmTmKwUg7B&UhhJ7zjN;##Ei>b`F@if%|B z4{lT6R_)JEG>w%)zD2hTh-z8id<}ZeQ6QJ``m;8!*=V*fdS+#=&awfqRI7^jlPTL?kZPsH_RPzQvN|k|3*c zL4qravJ~7|Yio?xCXcSSv0eV6Okl}#Qr~_izoVy;>7?SdJ^&Q#(Hs19zW$!4X=ghz;$f;Btv-%v`PZD+o(#c=S!rrpURmSv^ zE+%V?h8KcZl1ctj5x%?iqAwDbm1>kDC2LdTzlsb&=u|E8wZBrWRWAvbI(IZpvs@xL zTCPkFlO0Ji^wV6Ky8%LnP$DHH7KT_@C#^HJuz<`>j7z;Pym%=r7?-8X=KZ4bWxvx@ZtwF%abvB>aQ1V;XlzhVOZ|%ZlVDh zysQpJr3HG+Ci@MlYWSvGPP5t%!Pl`qby#P&8JL-GIOil^Eq9(*5%XWp$I#u+> zn7YyL!bV>>$1}AsX+W>636{!;yTR(__|$~V9g)copIwSv+OTfF{`G}G zlT@PZ$^@!!_N=y#)wD?zYJfTs#{o+v`7Eob6b|c?a=|7XOC6swA@>uCg+4js{amBF zMj^Npe~nkeKsTB`m}86{JQvjpNO%FUH$VK@bWSs3vl&ifxAg&%SidXc5_{Lz3oBfg zL+CM|xS&SU9OJi1QE&0+c6FH_K<4*2N$?y5{i0BQ9fDj%9|HIH`9%2eRX59({o}E9 z_VYSeTtZT~1xw{OH@!`j)egsQ7P#;{-50+I!iT8uzxr8+f%bireKVzTiip8D%b<}?ktn@B}Elc zJa%lj-{$|WeRg{4K0EsG>g@2yMKps`_n(}VvX_DX z_Lz*z*|&;axgok7ls-X)BREs849OgHiEE`U$d)9xeCpqLu~II{CHEJ3f=UyjdNgls zV)#AINCan2l+0anGHT&946EJ1fa<;RZZjx#Wi_SeJC|zhSME{pB8e7sv}7WHx_F&l zigKB-I5@DX5N!sl#>->*V)&M~vRF_jbWEaol#n-!T{!IB+hMzwsMK8EazZajN`yG# zY($35hv`aXLb!PlC$E$qKOqrIW7Uoprhmfrt)pZ^(UMqO4tVisx8j%)PQj#Hgk7o7 z0=&w=ZitbjGs1GY1f_DR1vpi}-4H30A>?$*iI}n^ZbPeDZUJI7kT<0l;WL_oqv>ak zBXYFLh%T(Oh?)x*o3yrL%7>Y`AIVj-XVsQebLZC(;snQZ*~Bdu zy33in0_2qkz5?r(b9W)Mo8olq*}E9tP0rz!)aBb}zWaPqVRFLD|;lx}Qk zwH~*m;;JHQ6UQyWuUw{a1XdZ6mdg#wSb5p8tLRidHPXh`;4H%vbH()=CgdqQsO0)u zhBeskzj|}0T++_~-&$p}d4ksVB&y9iT)k93tqm51H&^jsI!8fDWx1X5o8f|X%O%%p zHsh3mb1K2wKZ+pTP32`tiq@+%pB2%9&QFkYTlsb;ZrO?mbM3jLJS#Wh?{s^POt?DT zPd;)%=0gPDQ_mfsm0HQCdfgDwx{e%ek)e=4LA4h6EmuY9Eu>hx1Y6W}O_1pvfUj&e z%@17ftyc-Nf?!|LY?FLnh4!rivq4z4ps=JRPhzbiYD~$7311UwC7UK?F>wc}zI+M% z-)ru{l;Gm=ScxKVa@xOd15dJq@Zt!E_w#m8GnTN){3KH<>wu*~a%_{mwtif*#cz09 z`|(-vS-$^o4n1*}5D@a~x3PHtzrVY^JE-J;80@^*dEEbhh^Me>o;IF%1NGIg54mVp zqM>;6HB2pV>pLS05h&kGwP{Yp7JD{)grgAWa>}@gwlukKdY6OXf~N5h9TZ&-{6u|g z*iqHPmByIz)6W5|m)d;p=x`yNcN-P0KTf!sN3NDb?z);V{io>Y zOj}QtZa3h*vv%}m9sLHg!KM|@lah_ygb|c+;aAn2hk8k0wY49%T8FKTnS?V6Tj*kl zK6W~vD*hDov7?O9&KBypBQL^~x+HuAB_>3w0y;m_7V0EaNGMZ*j8z`0~1!U;_$P0fJ5Q0uECW3er(xMIy2u}t37)!nKS!mu`62D7S& zSx*YqZ+)yYNhzIN`?RefxDd0))yG3UYuW!Jlk{NCWxx{qfAC_jU$OtUU+g@_|31j` zX#ZF2f0Nkb_RD}$GLnZ~4K(B_x$6bODoxz)nt>(6M5kGGv|y+Mgz783+pq6LZu7Br z4g8Z*DEeAWv_`R`;vE0#d7ZplgBGdN736=zk)riv%o6$Ee=&GomH+)0kMjRPp6itp zX|(NnRq~NE?|s#!av^(dg&T_8@^x35No!Navh(V5<}QV`?G)^k4bh*ggLETM#7z6J zySKKL*O~v-vvRApv2^}#?^Wji&dzTCasEHVvvB_Vhc3Sz3E*M<_mKn6yK={ZV2$~I z!`+`%^nZ2#r~l$n|3A#LSpOG?z`vR4|2XB>dX~@s;{K?6n*Te`2iw*C-+uqa`kkx1|fxR-#lr zad&G(>Iwmf?v{iGFnJbZNlqlkl1%19|G1jRvYaIe%Vj7`In+63NkY@fFHpVH9vE*b za=*9>lJ{TUFi^hoQ-=ro(fn1+p`c}VGfI`40~@c0TanhwlIr+Xm%A=DGDTZQ;5bb$KC1cH*Jp5Ob`@zUd~k^4w8nUtx)%B;2>9OLcrGol3%|4(ezj z+Cd$2OIgRubGuH*I_RlG;m_tv!yNvbo6Ry{%7lDRl-4rZ*~Au>Xn+NN;EWF0=n$Y}f3+?ZIRG--A4@ z_FpCc*8&63mHa!d-~KkX-*u7T+@Vp#zmy|9Z17Iy;32#`fNMO;qEFShq>4G-P$3zg zzoj!;J+@dcpsRjsCaHKdMjwsQzlSmUZP{86Yef6zv%WRqYqp3$Siou_|pA>#oLFFjH+Zs7R~f7w~aCR#>Lzov3TFb z-2NRcOXrePJv@aQ=v}t0CTm;0*F;*S>n;(vliIf++l;2iO(vnwDP9><34dN*sVLKI zYb|SG-cjK{Otc0&c}T=%m`ZRWsFvYj=#9V8EBm0^5@!%dpdU zm8*Bxxl`f0O&{WQDGlsRH0pN^()AWr$#=K3O1^7zB(1Y(Z2)2i<5u3Xzh;ZnqHZ{| zlvDRYW{n#*3-?hH_HWny|GlNt$%k4j~#HD1LtVT!>Q-#q|{s1*sqqW4wzLCb<& zK$`Y)0r&4C+Olrb62R!ib&F{Brq)5G1O|E9a zojOmL{Z%bB!qEjO@|)YogzQ&e-%2!;AISe!dy7z-&qjnBq`lm4%SNf&?LMaYczoQm z-2O9qSYPUTBP(#3|L6Hm_58=+#qOj1_aINj{xgHEy}tgYkhZ(t`=3kZT9dW*cl6rS z*1~0q-No+U5{M6C1i_Uk-`2jIvB8GMv?yI4P$E01OOM{ATL)0Frw0Y=StTuSU`AcW zWnnw2Y2u7C$s(3`rR}SQ_F0R`*3NiI!miA+$j=Oq;NHRJ9hcPrt+Fk%Sc-g>92r9g!*u#N(Ld$SgwRn>DGH>;Ehs-S7U-VCTh)`u@-EqyB%0r(ypm zWAQ60c%CVx^HUyAh+K5vh`$F^@!|N|z6okk)@W*NWgOLu{vAz;s>5Lc`DZlUzr-|A zgW$Gg+?#S{+m)(YA=M}~8$saDzofW=L+RaeEE+(R@pzz6bbVz|9Z&Qn2@(i|;7)J? z!9s9%cMI;p-JOTKy9IZGySux)ySqQ$EWiKmm))xUI@MFv)6=*6-qYut&bE;f+`O#y z1Djk&6eue^c<=CiYHe+;f0{fOdj^Q*YQZ2AxV5miAUWgOJ14wT+7YRlPs+^x+f?;h z5jfwGte0sFB%`&sK!-{qWwdZ_-SP`nSmuwlXyD&p5vcK0nyTLlCx1h%CIi8$lhd!B zzhi)m@sNx-tt+rGwGZ|v(ETp32sei$cW+&T5B<4iZZ^L(X`C%M`YhiTmxee|c$UO= z=DBs|dRC&m=KKK*AKLuWEl>~?OV-$`G^5uQ*mmz8CoDKQSWvvGX5N(DIzl#b{Nq_Y zy(Gd;qJ=!o7z*D`4#qT57u|_RDtd^+zTwyv>Z>M~8=wDTvX;QR`zHetEek;fvU|H+ zBy*S7O64;4gkm+R(K7(sOrA0Fj3SaDiMRbn!N*ftxX-MxH$GEKH!DjPfgPS@Y04nr zT}66f^F#jMi_k2>MrxIqT3t{i$%3U9oe%=PsY#ny3_+6ViUpO1miME4Xl534^ zLIkp|VMZM?-|S~_**6A5EAY7J8D086CM|^Y;^c_IasPX8CLAIi4jm{4jrI9JY-kN_ z@;8Q8DxEjh=?$p;%z^4d$$GSn+zYiwVfxQ%%aEjz_7`F=7C)Q7?w8-fo29+=YDe>f zCl;~p1vxJVeLAa0ZIBE`de!>75Na<KpD$7^CbOxMWX zyZNEEg5G->i8d8D%jzKug7Qj{lV|^XtIzF$(09NA`S*8ig(6<&$`H6B>@UK6J<;^7 zcPBH3|Gto2pqu3Eu=Y3}|0kJh{){bCNrM1X;-cW3Y)EfBf&3{Y`QM>qbgw&sDTy$2 z_NN$m5`|BFcAuOi(MtR|zfHQxKd1Ny;!J>gkQ5z%)@M|DPVbSG zeEY)$NY3M%Z1sL^jr(eTalE}4LOP5RMH)A}GL)xC1hMBW4t@j^Hozyn0+F4M-zGul zcNWjOE|1?HK}37a^cMheXQl105!+si^NjOsTXZM#$goHy%GZ$8Jz6b4 zqx#Y<4n@qcfFa)Uj@ysT?MF71gwZmmPYHS7tO<8)lLdVWUUAPs2t8;KuaiYKVjynQHR65|{Ld25_oAC#9|YZf@`uQtL$dz9 z0}P+sDo!6e6EAZ#JYltFRjfw;@p!N;j7M}N+6=#xjdvQK_AA~ae`)$1^JqS(t;;95 z)!AKJ1MU<-daAkY^e=qf{C3;PGo-}$X1x!khDNe<(~K3;szbajfv~c<9A6dp%M}Sr z7mZdnDIkPlcLJ`IIiIhbe;Y`XJ+-r35 z^9vBv$cr_J_SV_jsyPZ&uY%fu^Y`pA2@H5&EKp!WWu)Y~IDMK^E%L4ezOg|yIjUUR z@czUN-`vKK8;Z!U8IC+e2oI{+K=tux4#{pgc&Jtwqal~ruYC7(*dy+Cbe5h&9GP+N z!4LRdk~8>fE;*x0P7>F5KBrdT^)-f2>HdVgXIR^3!B+nMCdg(yz@i1??E05~p?s9) z*R@?EI8gW~QVWF>gihOXs;=u=c+-gF>THjR+~P%1`$lCF3}Mh(tXl@Q6Udo3C2+qt zS{sJGZEoV<(L9458g$9mDfTE8QL3cj>nFvJGA3B*zrKW2GA&83WyLlEW~LIPPixX(lB8eSZX&k*0&0 zQ^}G9WdhM)HYu4Y^ieuEIk;jY;`N{jtCk}Qju!pVF_h^2Yz2+JLgtS?Z6AHz@CTiT zALkcAs`>hjR%oCiZ5?AxOr_CD{Y-M2M*K{+;dNmq1v!*JOtRm*YXOEO{!Rl~b^598 zvPDvOrU`GdSR_F_^tIW3j#oN(29Z948AQJ?j>XhzMaq(-f3hK{?OW=XXVUrX=t`86 z6Yi6cU#PRJz*pWjJ|151aq{dtb0fI+>9-Z_EnxFl_SkuL&V2v^rHGAxWI8y~3u_ks zM4OlqWnXdtndFF+Kso!45LU=JCiaWGNce3J&F;oSmO}t1@BT0 z=htZj68SB|_EP-)&_KIK=w7RzK7WW9p-Lij(a) zO*#ql1LAG4M8hWBqiCdEcLHR7?5Qyc#et#(q<1z+dGJLWtGNTFQLdSSvxiKc0x@(m zP9n$~XGB?<;Hh6slfA@COZPGqSLNsetIamz05l>i0cKoGO4Fr28NYc zWOOcecw_?Po|Un` zyPwUE%^1=&phSU`v~;|qZ7~=thBC)`_1J_5-P|35AZ3ADz)n%*cC_wgr~BheLz*sM z_&xA2F>xyi2DY9rWP$fetFP9V_YXNwJ;By-ESq_azXS?Q(f+WU5{X?L{9Sdy4c(u4 zV}2#a*l2jU(70VnA5DvPGFg6o#2=yXe)KO{xm(0*8*i7{W!D=Boq$cTU9p17i-5$> z*{nDAiaUIByEsMxirrg%l#Hw_Fjum{DF*8?;_uq_j6;UB0C{fOONxbDRck87HuPjF*RxL zr%z|{U{f967i2^~$drB@dHLs)or0s3G&rlJ+39-HB>oRFl^_{}#f8CU^GAZ?zp)81 zI1#g`)2v9)@j;Q(&7(rD@0$B?&-%j-kG?f5T)3T3j=z%dc|?*$@kk_adi z1@#Kr^_w%kO@o3`FD^3zdpTj$Eqzro-0&=TM^_BEZmxQ)qT>|m@D6bisr$L-Bk^l= zR5U_60tq}+UjwZD(!rHCZ+xyA`vdtDxK=XKKWw#M-nHLdhQEdxqeZags?w_0Q}Qvs zYqMUYMYho=p^0G|Fu}_%MP$P}>@1L@>BcCx+B2JECTms19qxIKs;!!pVL{Du`>s>; zDT-Ygn0`6my7(6Vvwf*!o}iF$zuB1f-nf@eGxw$_3!GEfgV0MZ;J#7Xyd3poNLm(t z#8eb54b3-`(vq|xjO^Jgf_xAaHQo1xi!#qsF=MCk6|@ltjhuk}QLg+{v`AlWtbJKk8Sy!wYJa=R#B51#Nt% z!{iyk_ws;o{1I0hsMEsB;&4_Ri&M><+S{Tb zOkkpMj^PliU66D~QkQ3DlfEnnnmY3YD-9z- zhP2y#?)d%d=oks~4kgy?Bjx1SB)OLeX{`1nU9^uYezcbu9l*UHAmZgHCFL~k#gVIE z@s$tdE24+_g-OvH%OkE*c!tYJT3z?s>rIAxDQ;Gk;6pA-@yEKe$dlK6+R zVT>{s&#Dv8leW8qn4HGph31Fe8W;hg87GXoOs9bM{8#E9*k0stT$JWWwo4kpp{gkq z>Xxo>zrgn7w8ORV8A2Uo#Mbg6+=ivSvby3ddc~%s+!HVy>fKb^6l>P3Av>ycj+=xb z>D{zP2C+k*AOcEB^l-FzPelWUOcD8T7;eas^f0~1C0exR07C3c5mUhEd-rr5 z)gR+X)lC;WHF1j+%D@g9l;h=+T3h>XO~VKrVt%6Ah}NXTXP?IT{7jS3(TW%k7!8`o z>}{=BWV}(~w*2tWX?-I;_NTFo&H(bPlG8nA@E`Bw@m|qkI)kel#OkXk?TW+GPVi0! zK{Em5|4_yo3vLJ0pwBdX(%}$mYw$@F33Gh zy-jCP&Cg5I;qICl3UND*oKLz{$aV0*lBo94*PsxHwC7S~q9N0oz(knn-b3(b6OLw+ zE!V{Qt9w#zWUKVmqGjR71M$!EFVH+i;gt34Rg#$hXj~0LE-2?TV_>e9CH!c(8Jtk4 z$v$JyC63G}7Irn`&fk)DlF#)EsPG{g71BDFRYMOa7!g_|6(XRHi0JF_;+vW(1|v;(o)HZyYZd3n;*6fzui@y3!baFS z`kI=LIj{QDVdz_RInOb_)5QY16G?t^KAo(^3LqfxbWd~-a4|%1Z)SN0P&b|^V>Xoj z^Igl<8m}};So&P7obX+3OeP2&uk2nZ_aBAePND}9Tz7{eDm8R6SCVzA#FSg3hs2Y3 zdDS7Gnv7kP+5x$RA%Mw&aFwJ%2Hnw3D@U%vBv7U|!1WUfkE&4l+4&Ky+sk)J_?Bcra ztLNMHWPgXo8DxJU!y#dW?ltMw6(o1ksb<_>!Jjto0*~CyhSluKi~tYf=dGaVdPR$p90bbTT56gvFUE!Df~Qdh3v(TFrO6?r;YQ&y`*g>3hXcWeyX1&M zB!<<_5`NXz$*)(~PZ($Y5O{2=BaR_s);EpWQf}dH!c`+9!?IL%dX|H7D+Zf=wY#>{ zEx_hy|7SD|j1D&cvGhxs^M>)4FO6cA{YjcKz8N1NE?^-%jI4K1>AksDzj z?x9~Op!=1oqRo_KxQl0KBu~}9-K`)uAqKFw3E?$S}@tk8-S_(-PcDR$7|= zHyI?5q9@K9+%3RM2|HWW`6gjU=AdxfrA-r)$lemxm&W}T6q=qYS!HqJD5lOu&2+-+ zwj%a&(WHJ~Y~g;_85XTFNHhg^lcw4A?`Z2O5#G^GF?J+OVOQekWWw$+u1bd`VBU#{NiuLc+?aV1-7`JwPLrdLe9t=fh&yKZA z!YOj1?-HOjmG0TH)#4Q0@wldwMH6gNEcC||k0=x#HVQF{QzA1^qAaRX?~xya>g5>i z-2#RK9er%^$l@Ra2b{l4h`a&Pwcji++m8&r-YDP@UPu<`oT!t}6Sytf5_8nEE`a($ z)yqrC^zSS2yY*EchSWNKKmmtu^bP^aM9LgKX^4_tjuV$9vICm0s+p*9#N;&mcLXf7 zn!-Z<4+X1Y0r~Wh-g2f<&F>_?(!Vhdi{n}BC^CG@4mp|f&k>tt@02E%6z8>Q>*tUk z?08VB`>3(g)>1jM;EVD%g?;c=D<+Gt&ExIje7m(*3Cb3^C}y%Aoz{p-|2V)lgisxR zP6IU~pHU$w(Zta#Vmze76ZhdhqyyZ+nG3&upK^hipiiGDW7q!_c+g2RX1Hy&UJon# z3b#dL)L0eF6!h7{eiX4zdRaxESumvVg!TEKrP+^ojub(5mP4m7AKk&Q5x*{k@9deX zr4oev%4MZ)&V2}QC&$n~`jOK)ia#oGT;Wa6_18ajEz`=CWRP{9F6`Xqev&|4`b_K~ zF!fxMy?;yhGlg_)zLYPOOeaJ3sHI0!Mz}uGoV*>3wAzaC_&*s<$*Pw4PDp%?wmza?P2~<_?`Lh(%blLqDs19 zy>37!qb`)<0(^J1)my(**??{vl8fI~9!JAd(3Y?)YQCvJWjTGxKqO5emjNRux8IVM zpCJX~3kleTOVP+J?(QAsd?-}^_3WF=O1#$CT#>+%=djV&7|IhI^we|dyULws|1AXDWmaBI?ZjZp*tZLqLB-eeh7CGfuuwY2At~Ivaei^ ze^Z50zZ@lDGs_BwW-@zB7;?4pV#qgU*N9$XrzS#O*tTKvQ=0a)7sh3_rlQ4epJhFe z8yIl3?>;-9P)I-=Hik8nFX1&-7i8h0hY<`M{+E+KTWg}B&Alyb7Dhh3$c3UWi-Gwg z4>R+DR{@=gGIe4X{XN$mYI^i)G8|fJjBB(-bVo$q()2BSic5G8fvH$t7h{BkIGWz2 zEeY;mZR2wUui#o2TDbytv2~(x?7tz>8LhcCDKTPdve-!&G6ULW(uqprj;L+DWi19W z$03}5)8dxNUGy(HyL+%_$7@Q&Q9Otmbe?o&b0=LnVLL@X@OzdyM)i#C=n?{y6Q+x{ zne8S7NJFWGA5=7$i=%Ed{AFcWNiYQa0v|3?p+r8X{nnZqOW}8JuRI_K5gZ@(QJ1WM zZ@dnkkheN>U)GUFzo;uok>S)kM;2kU=vv{1oy^Pup)wc5Q>Q#QyAf9uPna8;ct7LB zCK`J%Anmp@uN89CH|*P43&|#!+ABmIR_b(mdA+r{Zjf3i)R&m z&9}ZyADFOqH==N>3R7}tOzlX2Eg}Em{++=?Z!o-tB&(UBi3*rZkW8hf8!>UFO49Mw z#mW;zGK#sdf2fC!%8|nU;(1-;SI~aB%prb;jJmI9x_p_p7GU$cuq6#+MuX*rbl|&A zKz)t0;}N^U%HY)1vx9{T-zJmty8tC>!0oer^UniYg45U?m@_;Ptio~%hN=-Q%1`*; zdf;_JLW4v8p~@6*=qS)o2cqtfV?Xf7KwCNCukXv=tWaWJQ@)dg`qHdAR!K*iYZ~L4 z@9FX#9KGMU;+`C02APszT+8u~`U9g+KVEPf7ZQ_L+{pzUM^I2vC*Vo5A_*EvNP4vV zU-n0_Lb^{+9qzskygQc!hM$NzLiWS45z4r77K6~mXVSyzy9J#;#oVo>-V2eFXT}gO z@fQi_sNsHN!*N&9xyYK>HoAQDr}y@Jptdc+3!ZP_)G_9ZG&u4S)9rBd>++d(8jW?I z>Y37_DfI5LXB%#VwQm0)19i7A)!S&l%PJy)6F(Y-P&Zzc;jYlA?aC<3!+@;X&JpOD zCl=E?2J|%%R<@o6pX?dNN?uLQ*KhFV=GqtB4y>2dzQMBc8y9DW$_;w9iN3?Y3KM*pn`28hg(bzj6_0&V$~59FH90XgyI9xGkm^ zPt;f|y3mHw@r}_~Gw@~kn=G1E%Ij&)pk7X`ObMrdBY690cIbG^EMllu*_}Cx^X26Y z0vKtZ{v57^4`x`E=Nq{pS@GV;N)>Kqx?kJ|9c3F?1w3j5&p788}x4w=X!I-HKaJsPa`&QRK=t*VKMBvB1+RGay; zCP>h0j*?%Ezd^@Th+|rOb}3Go{kzq0pz>$*WPPtcWzM(w9Yh=j^Kmk&#*&xM*Cqaz zW79ukXK2ZSe3@qx)S+k6#DgY2tujE>e{fAHSw0Fla{kOpOSNHM5j!te_K1dM);mt1 zmP~8ljeLnPNeW=d+bs>{uo9eE^If+7;`HxHO@n2R8$G#bU&B={dkId*s%w6nAq;Mb zw?4Z-(rF?s+ky(hvNw4d6=zm?@^+~LQ!RWpfk=IaoXf4ZJt{`qo{N-c40Js7B-B=G zz1cPr;U)K6Ksjz!hyJ@t>RnjD4Orze=ZVvku#Sl?D?G})L}p!=O%4rJa!80o6*aNJ zDFRV_feDr!b3zWt!fbW#7cH9+W&Ko$TK|_+x;BrjK+J(1tDGG0(QiP`|;#CdRrewAPi#!7Gs!3~2fP_5Z%Msn$uftcx)l1o;{B@AKr1)e}}_dUSP9r4`MSRn1Z8@mmyiJwHEx9Q1i1AQgYpPioSX zfBV1fXc0qBWZbr)SQG7uzce>$^N&9~iX!*B2@}f-b0Ms^>>-m+J|G$y5UsMzH|rdL zfio`;oBV+W8_0#6Zw8HwJ+swqVXM<*Vw}VTxnf3yvGL&vRanNy&*@0k@KY16m$jX* zs4B3^m{a_GM-A-@U`Fe2A`1Pb8qu2?r(e4*6u37!X{#-lRT6W4A}`U-b}Sg`A{qDq zl-qRwDq#lrzqm=8?iya3+l+1o2BmLqi;>QBTBm*6{ghEyP<$me&!4zmr1b!^RvGiX z2#bi5g*!LL%+I~B^Gox(U?qmy`kz|mt2WXm`4EGUZwAJ#mbdv}2&N(S#L56G6k7SY zifRMQ{^Bpb!*%R-b{4Icm`3+s?w0kFPIa$oE+z@yVTza8le=)9%J3Xtfnr8+?MtzY z(7q`Rg6%k?dV{Iqt0$ScfWiZqUp3QZDY~%trtl@Ad1QM^-VYk zI+DSS@|)S{|97HHy18eU^WXuK(^P^k8_vP&{;j(X)%i)~H?QE_=kV!*80C{Ss?D;v z7o35z(*r?tM~+w7XWyh=5xJQ097Z?;LltDZ;lUoS_O{8icL;Z;>RQ9zjXCqT0I!6O z^D|x9*`|nGNuG5iPlged7cF7G%y`Nu@q<|`rh|GLo1LTT@J1OF+=S(*eL&2sinw#K2yVVPZEbYYa;F+E78PQoQ#sx z{kB$cBe@6f+rZVOu9ur!G=`$B-JS)-sGXp;-$y(i9U7NFS=~c>T*e>F&EF*GHOFfe z#%rsR4?u$s)I+x@M?Wo=*X&30+pWheZI~BRp3LS~#R~syzfq1%<6*A|7*)s9+O5^} z7e0mwUG8Gc9@=T7{EXPyc=)86Yj%#9H$p#lREMo8{kE+2W7SwJjo>CUPG)XD5wArQ z8*OEi>OK?}WuFAUT?0;lWIe?TYwC`XGBkde>*kqt__n$2myw_Bc3Q;|<3RyZtzbP# zsU?Cl#Gj!?VxN$n=$%iCL`LA2Ini2Lo=VuK`jG=l9=%|BhsRHRL82q?=k8I4m@={xFHIOU$dEEcbLOURPP9&{g&L zv1(MX6#2toS1M5R@%UF8UVE*IrbZK1U!r?(*<#e_2#c}^GKoPirQ)Q;LhvGmInCg) zSLi@Yt|${6Y#DCI!FBnQ@(@Co*R<}B&RnX089x1ZZVKy80vqv-vDybQ1&o=Db7Pk)c=UwYLSB5DW^7JP5==Z)La z3Vm$ZY|LP^{>S;HU*ZPV)bU!^#1}#ZOgOQRosn~;oYV42n*bngD!+#O5`;5KdbwG1A38!KT=nl z;;>*_>uFflxf`9{2!~zitO)&ISDc$3Yzp^BSo2exMoxq{=tJK;>N-f&JJ}J+;+WY^ zuWnCHeysniJSsTr9Ho8Wo!42s`Zkzu;G|mnVpulj!UjYC>XZB8M`lY7{K!+USx`2< z5qG{_ON}@XNUb-*(6rF5b4w1PuDL<1Cx1~LqL;H>VVEs+-T)eIv}ARt3}@2pECj3cM(|XTHMh zgO_#-^1FYfY=tO)gV&WYFVhe{cv|lA+@E&3uJi!3n-3NNWR5OHZHxIRW$=K#wtt-HH0z$nn7KYG)d=LhCPkQoFH8*V>%P4@zcimrd&HW?k& zA&bh;PoU4Gy90;nnIas@RP%sK1yt zx$xms!oc3l3H~XIa3-N(pRln59&ZJK$-d@YW%X6QAQyepIqavQLac8IDV#a&xR{%@ z{dKYps>qzaJ_8jNvYvrjV8MK_3XsD>Tr3}K5zVL0e+WD#KPDy+`M&}dQ5!LU6Z8p4 zTJW%9!=-eQsX%#aQ<{5gFQy}J zU9Qeu$(}B?vDjEf9CmA!;TKh9rVf* zqHQ*+^91I*qoOR2rEBrsXf64wb=ym)Hh4zbTUV;a(Iw*&Qwk(q>tFT*#Wr59j8Ip)*j8uQ#FKoDRjMv|Qcuq;DNmb-xXDaV)1tDXI>*I5NV0HpCJ-*IaC z3@DxM11zw%K$JPNXMjB{ts1PX$otgY-GRR(`*?Q?>V=f0`v6%1vNb@h+-G5*+1a0v zA`6z%($PpwSode$@)I-UF#DLIGU=#gM|2&m#Ni24>cLSl43@xA3$JyI?d? z6?Wwt+ClmjbHv+83QJjBi^^a`s-S(ajUxD(zJFPp;F;NmNM=&1%g{z?Z`;Md(D>S? zm0NDZ0PD9fDsuR~fdoh~VUbW&!TWL2phUpibt%dOf3jDd(y8suNz~CP`FXPk_|y#n zG4=sAqfa22M*a7XE$jnEQ%UsE`FQTJq}+fvwoPpi$nEkH67dbPh@`Xw8lV0EFn#eV zsq)O!QpYAyIJSHcN<`QF_gkgPqYbNaqSPDT`oA!k0A7vrBUU zFEXtrVy75rg}xv8Yf0UB?=+9s?3q1lI!&jSYSE#tSac^y<$DLUH%NxQ zB)+EB;-qWoCAXANktcvAYDyhFr|G;Xr4oAJyFR9c@AbHNV0f5u$MqYhQrQjWVFQrX z8P6v>3r?PA8s*%7zYs)*Qf_1}7L|rc2%J;p)RC4>+pU8Wpu-aA=&WlbsGarWukAuc zMWwiU6LZvUjh{sIqo+)KpRo&*;%a+a-oKSBY8&sTgSWx2z%t{s9534`##}2Tk81F^ z1;=^BRdxSU&tdQyJ&Q{=|OcQozrRO?Azgx7)L4WKxPkjV9L<;Qn=Ca zuhu-LO-?R8RR)&%w*38Sg*dISddp+~R-z?mIrXIa6Wc+julrqE7+z{xrPzen8+j}( z{g5>;Eo#24kdgMrybeu z^v-r)qRR|SXuK2iG{KYF|%THqe3a#R9qdNi+w5{ zd~VWoo>zo)llEa-vBqw;HqM?cntx-yflbchOkB;{C_$H;V@?+Lyd(d$&fX zM@g5O<~qi=75Bi;S3W75RT8+nV^A91D~O;ABrEK327vP~N#LrGMu@-MNkH2LZ0=^e zF5CMq{hDJEG5f3~^oez~31q-9`MZ|GVjp@vqvKjUu?m$*`Mk!d>#c;(jX3H-9T>j! zNVsc;bzcApG40=P){p>`%*^g@*p%9852yWqwHzYj{w~}lVeT5y-R=7nyvHfcK8T82 zkbdRF(8WQszwW!)**0zX>1`Gkflejz5hdff(ToTd(S(d5;iI-CnbYyePUV1EMV#5G zn{4WlY4#lKiX4+f``e$xP(cR^zW6@x$55H0#%~Ns!C=a-&8uh$M$g)KHrAIX((z}? zXPeoy;q55%Q&=n6$|-)|$PqsLaDx=4F_Oq;d6yXl_w2z(-q>{3t1#$PmgJsaw9*A?6P8e3WWuTP~Zx-P_=0=Wf)xB8h~2 z&ePYdCte8$CO5q!o;_PoIZySJgGZo|k*xafv0P%taz$@^E}o;^P6=S_O3haphX@(^HHM!D7bJ*WC6i}~0ODkP4)Oa;7R^x0sG-as!& z&qhVH(1?Rk35_k@sZ5BRq-g?QIfo2 zr)scT6R(NiyE~z;rP$>it62(PN9ZC4WbF8}^s;-Zt4T zy`L`*23-_|U;=M-1y7pe{7}SrYk!QAFFU7U$E0tfBK>l*#46p3J~xzC^|m@)lWhL! zIM{*Qx$joyi&H7VFXAAykeL(jZ5?Ec<99&1+wyhIGaQSqN6UiLM^&3sZAWLkk;LVI zB#QO%sYPuTe{{#oEKRuDb6jvjT`*)2CIXV}!wXKX7<~rO3e^e# z>3#zzAaH)8CXiZ&lF*@@z-#2Qr91MX>}3Gat~s|CJb1sA>Ib@dP<|j9UapZ+{uvfU ze9+zy+X#`(XSP-Hp?s2`lIOn%TUYmC21R8xJ6JAk(_w<*_OzXv-0$fbYf>Sao{FGG z*losGBase{i>kE@Q#^J`u{(?MKIkgZ=|K!wfultCS^O%jEWd|M0F~vZB`UQ018ANV z@5yHM0|1cM?LsEyUVbxX3nTe5|CGf`F^3G^0^O&4#ZmN!029)uJwU>A2E6I{RJoAc zCuH&ftib=G_rJPg7J|M-{hh&oEklmme58EH$nnuU+ZPuF6&l*}_Di(4SM-ei?AG(; zK2R|wav{7K_MXc(WB{uQBoGU{Gc0NE+_TOt@?GF+6XP<_*9y+LzifX7_;rcvj3JDcD zd(2P@J>QP~KxXviFWrXqPFnyNv6ARFrtJ1+*^0%x&2_xE&PDmrfUS@-@&|1l?nvk) zO&0eMEsyviiX3Vqi6?|jW`=1xdkN@eX+rdS2Pv}FpVEzHJE7JmRyGU*mc^61LCzY-~9GYpoc(CSi$Rie4`8dPr8Fs0+93o(LvyId^;UDS?lS;CDhx;+e!jxPuZOI zKlTBItmKZ5y~5S);ekf0Q5I%Ft&Y%Q_uBboruwk&EFuVLS4-#A$5mZ-EXC^G7Ab6t z7JR)$+mAL1pG2zpWC>PR31ll=P!~>=fy`N3kF1g)>tL|KnC&>B{ zZ@*ftxsK@>9Cx2Hcx;IqUYE>7PBI~>*WM))25N2Fnxmm`ti`mayk8VZTz=f#M@A$F zoQ^`z7XhiI5r7Nr6i`Sq1UO!_5bc5RD#_@tdmON%b~z!6^@NLkQFyK$^>eY^onI0KyF)>c@UWj7scWS01Uv(|<=$ zFS<70iod;8QULMi?082YC6ql7CryEzFIX<-J=9Qd_&yNEA~ymqhrTD_fb|~emvXNk z_-p)s&E(AVN}q|k0fX^p=mC&s5ZP^KiNIU*`#_PpXpW3NRlTTV&>C}_o4oneM zv6X)jz_Ix#1# zpjI`5fA~`9Bt%?k=ISgbfo~tK`JhhSTdL?o0N*E~5a8H1hsTV3`HyL3je`3kv}E2B zYv`M_c>;*iMlhb9Msz>f>5gjo@19sd1(8RVt%ePcS2W@}jr*v|Ay4@vFGtFGih?lD zt!PS9lf!~#nHSopNd?fXCM8mgYf&Ne(fil|t6T3yNEZOgJOPw%JGp?bmC*BpK#SGr zy{-!4O{bjT>^x{Yj16;h65rjUn=s&enziJCu9p(;VbK$-VUZk<`DC!@6^P^?9sN4Vly8ie1sP61pmvaUFfK9NH_qDcj1nZhSH&-K%*m@dMHvmf+{384W=pts z$o8mDx$1ZrmOhk}-Mq8@4%bYl4Fmk$!fwcXo#XVqyDS^hfPSJ-`8KfpSS zU9}fW>6cnfI-hdbhg5z^l9uR`kFBpm<=d(=<0H`vJaEPQq`4wq!!4UWDTRJXiGaRl zFLs<^%7YnrI)2!|1hSHMUUc56J|Bl~$hFIOg0U%Hq@zh8v3UcBu$%`~dF?9gri)+G zL1@z}8`rs2D?Gur_eA5p{aX!$liz9^dXJ60?uUoWHDfoO6aT2K*o#z;h_c(9cjHm? zTvLg9`{#`kYaL&;Fl*Wke&BCh)%@rq%l-kX1v@b*EdoT>r#$#U_)(ePQ7+|S9`NV} zLEm(8lum~LY##tNgb$F*jCoKOz;X@hu)tq(a@zb^UD)cn{W2P8MK=~`#C6f5u@t0A zOO5zXo!)+}-@uGkYn2h@##7s=ENPj@2Y?0>Z2?dK8zjdEusDa=0+3h0p;w?dg$y*H zZ2_?%8#2;5%P!FPCs~)8uTLGq=uOsN+kuj=V+hqKcx-&n5-dD+UIyIzbvk#0j-z&c zApdphlzYCjlMI56qRfQeI^U-r(IG7a8j=?Z*dk4;nTPN9*m2 zTKO_-i%j$|6Eev=jZSCiZM*qaJg3>LIKjZYLSMa)2o(6!7T*9L#uZWdUv@F@r+6)j zN%t_mJv&l94A6j1Em?UPzSnsffyuK9mOibVtKCD7JFCc-@4>lOky!p~D^xC|TEWlh z3o_Ch)(0br_!ao^3oNO0wS1~=`OT|s_H4^}_#horI}Q-b>ddN@(8}#aWJ4y8G2G_& z=Uo^57Bsf!0e*hT5(P*2x6ZH7%y@udaT45f79~j+kWuu)HxIt-2K*WMdBBw=U%=4? zW%7U%S{gFofZtCa7B(xbj7CwQuH>9P+S*DUsDg&WuvQQ6ER$2g`~`ffJF;JS$5go9 zN^X(>0@8n(r#mhjC6a!~8xF;VWE34OYW%QRql9M$@89p@Ju(w1G46kbmBV5~(D+h0 z$}Cz*eWGXu3saaZM799967obzf%{FFAySPpgg1bUpbx;QiXi_1jJ?$f1;9Qrbb-!i z1-d{VAc)2B&PhNpIYfVs40vDg4}oeV{2jjUBwe7twNGFFYx&;jO4kSY_}|O#36X+; z>Li{ZOjWk?iaLNF_Y^#B3XZl;f47-`f9bzrV4DX=?*j^d2~!jBpj`|RgXf|u)a{3quU(!{ z2hcx>UL8?>68SR{wT^=BLwP?`O#(Kh_7LpR>h}ydK=c*pSKow#Dz1QGv?baEg~e0d z$u}q>-JFupYP^w*eVzvw85~nT^fEysU|>H{g)OR?zJtnSRegw)+U!xMPg3*FTIgKn zTh9wKi-d@ud@Elb?6*ngdslh{WcAEhZ@A}$qC%k;D>RHj88~E9jA>ffAE==CKN!)- zZw;yW+VTJ}R$PDz6c!?#_h!l9xNml|LM^!wsVdsZ0fO#nOLpk{a zzVQE> z`ajDpDa=!4-fm|mQrj^?PE00q6#Nx07$17$u&b^S%m)Sc9v>EkWP`v;67tP|J+DrrnyZGIoH)F4L3t^u- zi*gXIi4q-2dt#|+c3JGn&XRwmk@omB>MFIq;Hh4z6XeI&avBEi-5D&4B-~SmNd}vy zUgq)+rO|(d-{=fdl5;-3Z(Wwm(s<)f!t(pZJ_nB824sQ`pBz&5w_luf%wE8l=VgLK z09O>V`+AD6mo-=NjLx>AdBR6L!jA%3>2E;>rD(+k^t zziRjAn*eWr_-5-UqkB4S^yQ&ZZ>~(4{l$8K9Hv3w8ec8_- z?23VcLG!s|1_x+elA-ySCP8X$LCU2nGJbLWUzXve`3HB3>&%#B&T}xarndKNsOZ4M zSRn6Y#e7SJ2u{w8f}k(nquAkS?D>#ISlFX!AnlnCY2H2?@=6W^0csUrFou8+&wK$` zB*3RB)MNNp5cKC?-+&wotoKua_w_KNi23I{`0)m`K528q{bgN-UKp5F;flUDE)+8VD1Q6EIw zQGkqXEz_o?J`}?5JhZH~eLvkqI3h%}*+mtM z8mKN?5vw645m(QXb0@UjR%SM1a37LXcpCH6%e^%>c8hdmd)kR#@n-9_TJzl$%RW41U-fb*4 zYhB7Kb)y8a$U5-%F5Id|*%MgiBDrYE&(~S=ofllcOfFgRExQ>Iz7oF47<9h&QQm1r zV_V31#|N)jA&k_3=_A=1U7T>BxiDYZs74JK$hmkf<7~R|#uAAmFI5wxoRr4Z!Wr7n zn~4JZAlEDvEWhTrA>njoKyT|6YooBU?KRy-N|yy|Cra7HsFyKrA(KAS{y z*VX9xLvEA^c>%H$I#E?U+dHxVU!8saG#}U^pMVu8{vLzfu zP!^g`3OYD#X%Mam*0OAMMuFK7bn+ANfmU@wW#yh7tk5i@Ir|y{kT_Oc^G#9#WB~yG z(>oJhjtYGEzgoD`sHTo69EhwMilR_twWt&+f=CgekN~AAmc^pTDya*iCQsU@VWA_WRU!kU0^NC-<}Uf%Sj?fjcFGk5;Xx$`Y|#+N82 z%=#lg?U2sa6}hiMo<1}p7l`WBR#66c6C700G8L=X9G)(-D75N7u?80Zo07FiKpIrs zxaWvUGD(^O7ky|78J}$;C*eAPE6$$@KL5j*PGqMZ{k6Da=d&xE&6n7e>5$^(02`cd zz>1ZuJ4j z8obiLMj43nXhYW=le_DP(H`F}%xvc1T)rth)n~p8EctvRI!q0M8{(N9-DR+K0|M3k zBDtHfvG}A%0_Hka%sYsQco`+e6c{X`?D47LNO%7)Zej93*^fkDJCB-bXB|S2 zLHdherzl{;P{Jo^N@7E_vezN55A5D?3rri&Bx4SjBsbd_GQH%(WdpJ@tp(z-RdCP-8~pvjZhm^_o_qaxroOfecE!%Ykg1W)Yh@d3dlK`9>Hp3=?tAf zN-n=W`}d~VLlkTHK}uV1$oO%1J)8;IxBLCYaa}EMeBJch!keG)RX1tf_JM4!kG;^- z`MXkXmT%&hQM*q!TqA$-;fK$H^CwS8GoD&!8{1D=qJ|vBOmRPP0pfN5aPIyTX)w5r zXXxQ4A(=eLl=9BR7oR2n&P)*br`O&-6zJ4RnO{1)Z`dE;&mtk+>}Vx_zz+Qw!bZfK zpvFX!LLRS#?0f#yG2ro7?bmEOgSa1Up`#aOrk8)oT`fxSpBo+<9o!Zl-PkvtVN_>q z^A4$CKkG7C>VsOk@>1rTqb=T#%Zu{wjb0Z1`NzAaQtGBr@*FPC?TmCaqh+$};950m zeUWPuQr)U{%@{5u@jd$L5RPns!4j)J^ACKr_tXwK%WqT@Uf;Pv!ip(gu{jJZ+VD3FS>Ma7 z2LL{4gbMJ7lpl?ye*ii9um3-5*+Ot?ntE3XiL%rr{G7h@RgmPF67LvEy}GIK%KVO$ zV@`KKi+?V6z3b)vL5+7p5Nvm39N3w`P>#Ng+M6H^X$4Iz5b{^#Y1fhdh|)?kL2*gr ze2{n6lkmKFPJQOSHF3Xl4QJ)(`82vub!2I7_7|s_^|r1duRy1WfRMzZJ*zwEM58Y_ zfgO((MftV89Tz#ggeyiazG;*agvhu>Bnn zjZ$Icp0|)XmkTrr7=@UchgOWRDzONPhhTo=tuz`qVu{+!lc0kl&WhK>58V#mb?gUo zZBK%hx~qO)T7Nf9@0z-Z@O6c{)9tlERTSA_nwzdq9UK|hC zK%9Q-8yVg^*sc}$q2TlXREvU7bblFXzlq$!?sqkWbzO53)H8i!>f&YvM<7dmv>mop Rk}((z0MZ6VC}z6`<{!O&uH*m! diff --git a/spartan/metrics/templates/elasticsearch.yaml b/spartan/metrics/templates/elasticsearch.yaml deleted file mode 100644 index ef3bcb72533..00000000000 --- a/spartan/metrics/templates/elasticsearch.yaml +++ /dev/null @@ -1,72 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: elasticsearch -spec: - replicas: 1 - selector: - matchLabels: - app: elasticsearch - template: - metadata: - labels: - app: elasticsearch - spec: - containers: - - name: elasticsearch - image: docker.elastic.co/elasticsearch/elasticsearch:sha256-ca844065f663d0a91fe82b4d540ad1e6f4c4ddc58b354cd1724bf19e56f01409 - env: - - name: discovery.type - value: single-node - - name: ES_JAVA_OPTS - value: "-Xms512m -Xmx512m" - ports: - - containerPort: 9200 - - containerPort: 9300 ---- -apiVersion: v1 -kind: Service -metadata: - name: elasticsearch -spec: - selector: - app: elasticsearch - ports: - - port: 9200 - targetPort: 9200 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kibana -spec: - replicas: 1 - selector: - matchLabels: - app: kibana - template: - metadata: - labels: - app: kibana - spec: - containers: - - name: kibana - image: docker.elastic.co/kibana/kibana:sha256-ff5f6b9a49f410658b74b337b102c302bbeb52b470efe1f0e3af3c7526fbe0e7 - env: - - name: ELASTICSEARCH_HOSTS - value: http://elasticsearch:9200 - ports: - - containerPort: 5601 ---- -apiVersion: v1 -kind: Service -metadata: - name: kibana -spec: - selector: - app: kibana - ports: - - port: 5601 - targetPort: 5601 - type: NodePort diff --git a/spartan/metrics/values.yaml b/spartan/metrics/values.yaml index bb79b6d1aa7..96b6bc8a855 100644 --- a/spartan/metrics/values.yaml +++ b/spartan/metrics/values.yaml @@ -1,11 +1,15 @@ opentelemetry-collector: + extraEnvs: + - name: ELASTICSEARCH_PASSWORD + valueFrom: + secretKeyRef: + name: elasticsearch-es-elastic-user + key: elastic + mode: daemonset image: - repository: "otel/opentelemetry-collector-k8s" - - command: - name: "otelcol-k8s" + repository: "otel/opentelemetry-collector-contrib" presets: logsCollection: @@ -16,7 +20,17 @@ opentelemetry-collector: config: exporters: debug: {} + elasticsearch: + endpoint: "https://elasticsearch-es-http.metrics.svc:9200/" + tls: + insecure_skip_verify: true + auth: + authenticator: basicauth extensions: + basicauth: + client_auth: + username: elastic + password: ${ELASTICSEARCH_PASSWORD} # The health_check extension is mandatory for this chart. # Without the health_check extension the collector will fail the readiness and liveliness probes. # The health_check extension can be modified, but should never be removed. @@ -24,70 +38,22 @@ opentelemetry-collector: endpoint: ${env:MY_POD_IP}:13133 processors: batch: {} - # Default memory limiter configuration for the collector based on k8s resource limits. - memory_limiter: - # check_interval is the time between measurements of memory usage. - check_interval: 5s - # By default limit_mib is set to 80% of ".Values.resources.limits.memory" - limit_percentage: 80 - # By default spike_limit_mib is set to 25% of ".Values.resources.limits.memory" - spike_limit_percentage: 25 receivers: - jaeger: - protocols: - grpc: - endpoint: ${env:MY_POD_IP}:14250 - thrift_http: - endpoint: ${env:MY_POD_IP}:14268 - thrift_compact: - endpoint: ${env:MY_POD_IP}:6831 otlp: protocols: - grpc: - endpoint: ${env:MY_POD_IP}:4317 http: endpoint: ${env:MY_POD_IP}:4318 - prometheus: - config: - scrape_configs: - - job_name: opentelemetry-collector - scrape_interval: 10s - static_configs: - - targets: - - ${env:MY_POD_IP}:8888 - zipkin: - endpoint: ${env:MY_POD_IP}:9411 service: + extensions: [basicauth, health_check] telemetry: metrics: address: ${env:MY_POD_IP}:8888 - extensions: - - health_check pipelines: logs: exporters: + - elasticsearch - debug processors: - - memory_limiter - - batch - receivers: - - otlp - metrics: - exporters: - - debug - processors: - - memory_limiter - - batch - receivers: - - otlp - - prometheus - traces: - exporters: - - debug - processors: - - memory_limiter - batch receivers: - otlp - - jaeger - - zipkin diff --git a/spartan/scripts/install_eck_operator.sh b/spartan/scripts/install_eck_operator.sh new file mode 100755 index 00000000000..5923893ea61 --- /dev/null +++ b/spartan/scripts/install_eck_operator.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -ex + +version=2.14.0 + +kubectl create -f https://download.elastic.co/downloads/eck/$version/crds.yaml +kubectl apply -f https://download.elastic.co/downloads/eck/$version/operator.yaml From f7b03b7a3b5a18051b423d556e111dbbf64cf7d4 Mon Sep 17 00:00:00 2001 From: Mitch Date: Fri, 6 Sep 2024 21:19:13 -0400 Subject: [PATCH 5/8] proper json logging --- spartan/metrics/values.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/spartan/metrics/values.yaml b/spartan/metrics/values.yaml index 96b6bc8a855..d792b7d9fee 100644 --- a/spartan/metrics/values.yaml +++ b/spartan/metrics/values.yaml @@ -38,6 +38,22 @@ opentelemetry-collector: endpoint: ${env:MY_POD_IP}:13133 processors: batch: {} + transform: + error_mode: ignore + log_statements: + - context: log + statements: + - merge_maps(attributes, ParseJSON(body), "upsert") where IsMatch(body, "^\\{") + # https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/pkg/ottl/contexts/ottllog + - set(severity_number, 1) where attributes["level"] == "trace" + - set(severity_number, 5) where attributes["level"] == "debug" + - set(severity_number, 9) where attributes["level"] == "info" + - set(severity_number, 13) where attributes["level"] == "warn" + - set(severity_number, 17) where attributes["level"] == "error" + - set(severity_number, 21) where attributes["level"] == "fatal" + - set(body, attributes["message"]) + - set(attributes["level"], nil) + - set(attributes["message"], nil) receivers: otlp: protocols: @@ -54,6 +70,7 @@ opentelemetry-collector: - elasticsearch - debug processors: + - transform - batch receivers: - otlp From ab6aaa9102bdf9a68a2de2991d3815ab883618cc Mon Sep 17 00:00:00 2001 From: Mitch Date: Sat, 7 Sep 2024 16:25:00 -0400 Subject: [PATCH 6/8] fix transfer test --- .github/workflows/spartan-test.yml | 5 +- .../end-to-end/src/spartan/transfer.test.ts | 87 +++++++------------ 2 files changed, 32 insertions(+), 60 deletions(-) diff --git a/.github/workflows/spartan-test.yml b/.github/workflows/spartan-test.yml index 6ed63e39900..901dbebdb5a 100644 --- a/.github/workflows/spartan-test.yml +++ b/.github/workflows/spartan-test.yml @@ -136,11 +136,10 @@ jobs: tester_ttl: 40 run: | set -eux - cd ./yarn-project/end-to-end/ - ./scripts/setup_local_k8s.sh + ./spartan/scripts/setup_local_k8s.sh export FORCE_COLOR=1 export EARTHLY_BUILD_ARGS="${{ env.EARTHLY_BUILD_ARGS }}" - ../../scripts/earthly-ci --exec-stats -P --no-output ./+network-transfer --values-file=${{ matrix.values_file }} + ./scripts/earthly-ci --exec-stats -P --no-output ./yarn-project/end-to-end/+network-transfer --values-file=${{ matrix.values_file }} success-check: runs-on: ubuntu-20.04 diff --git a/yarn-project/end-to-end/src/spartan/transfer.test.ts b/yarn-project/end-to-end/src/spartan/transfer.test.ts index c47a4e8876e..a472218d3d5 100644 --- a/yarn-project/end-to-end/src/spartan/transfer.test.ts +++ b/yarn-project/end-to-end/src/spartan/transfer.test.ts @@ -1,13 +1,11 @@ import { getSchnorrAccount } from '@aztec/accounts/schnorr'; import { - type AccountWallet, type AccountWalletWithSecretKey, type AztecAddress, ExtendedNote, Fr, Note, type PXE, - type TxHash, computeSecretHash, createCompatibleClient, } from '@aztec/aztec.js'; @@ -35,27 +33,6 @@ const toString = ({ value }: { value: bigint }) => { return str; }; -const addPendingShieldNoteToPXE = async (args: { - amount: bigint; - secretHash: Fr; - txHash: TxHash; - accountAddress: AztecAddress; - assetAddress: AztecAddress; - wallet: AccountWallet; -}) => { - const { accountAddress, assetAddress, amount, secretHash, txHash, wallet } = args; - const note = new Note([new Fr(amount), secretHash]); - const extendedNote = new ExtendedNote( - note, - accountAddress, - assetAddress, - TokenContract.storage.pending_shields.slot, - TokenContract.notes.TransparentNote.id, - txHash, - ); - await wallet.addNote(extendedNote); -}; - describe('token transfer test', () => { jest.setTimeout(10 * 60 * 1000); // 10 minutes @@ -72,13 +49,13 @@ describe('token transfer test', () => { let wallets: AccountWalletWithSecretKey[]; let recipientWallet: AccountWalletWithSecretKey; let tokenAddress: AztecAddress; - let tokenAtWallet0: TokenContract; + let tokenAdminWallet: TokenContract; beforeAll(async () => { expect(ROUNDS).toBeLessThanOrEqual(MINT_AMOUNT); - // My guess is that is never proven so if we are waiting for it to prove we wait forever? pxe = await createCompatibleClient(PXE_URL, logger); + { const { accountKeys } = await addAccounts(1, logger, false)({ pxe }); const accountManagers = accountKeys.map(ak => getSchnorrAccount(pxe, ak[0], ak[1], 1)); @@ -89,7 +66,7 @@ describe('token transfer test', () => { logger.verbose(`Recipient Wallet address: ${recipientWallet.getAddress()} registered`); } - const { accountKeys } = await addAccounts(Number(WALLET_COUNT), logger, false)({ pxe }); + const { accountKeys } = await addAccounts(WALLET_COUNT, logger, true)({ pxe }); const accountManagers = accountKeys.map(ak => getSchnorrAccount(pxe, ak[0], ak[1], 1)); wallets = await Promise.all( @@ -114,48 +91,44 @@ describe('token transfer test', () => { .deployed({ timeout: 600 }); tokenAddress = tokenContract.address; - tokenAtWallet0 = await TokenContract.at(tokenAddress, wallets[0]); + tokenAdminWallet = await TokenContract.at(tokenAddress, wallets[0]); logger.verbose(`Minting ${MINT_AMOUNT} public assets to the ${wallets.length} wallets...`); await Promise.all( - wallets.map(w => tokenAtWallet0.methods.mint_public(w.getAddress(), MINT_AMOUNT).send().wait({ timeout: 600 })), + wallets.map(w => tokenAdminWallet.methods.mint_public(w.getAddress(), MINT_AMOUNT).send().wait({ timeout: 600 })), ); logger.verbose(`Minting ${MINT_AMOUNT} private assets to the ${wallets.length} wallets...`); - const secrets: Fr[] = wallets.map(() => Fr.random()); - const txs = await Promise.all( - wallets.map((w, i) => - tokenAtWallet0.methods.mint_private(MINT_AMOUNT, computeSecretHash(secrets[i])).send().wait({ timeout: 600 }), - ), - ); + for (const wallet of wallets) { + const walletAddress = wallet.getAddress(); + const mintSecret = Fr.random(); + const mintSecretHash = computeSecretHash(mintSecret); + + const tx = await tokenAdminWallet.methods.mint_private(MINT_AMOUNT, mintSecretHash).send().wait({ timeout: 600 }); + + const note = new Note([new Fr(MINT_AMOUNT), mintSecretHash]); + const extendedNote = new ExtendedNote( + note, + walletAddress, + tokenAddress, + TokenContract.storage.pending_shields.slot, + TokenContract.notes.TransparentNote.id, + tx.txHash, + ); + await pxe.addNote(extendedNote, walletAddress); - wallets.forEach(async (wallet, i) => { - await addPendingShieldNoteToPXE({ - amount: MINT_AMOUNT, - secretHash: computeSecretHash(secrets[i]), - txHash: txs[i].txHash, - accountAddress: wallet.getAddress(), - assetAddress: tokenAddress, - wallet: wallet, - }); - }); + const token = await TokenContract.at(tokenAddress, wallet); - await Promise.all( - wallets.map(async (w, i) => - (await TokenContract.at(tokenAddress, w)).methods - .redeem_shield(w.getAddress(), MINT_AMOUNT, secrets[i]) - .send() - .wait({ timeout: 600 }), - ), - ); + await token.methods.redeem_shield(walletAddress, MINT_AMOUNT, mintSecret).send().wait({ timeout: 600 }); + } logger.verbose(`Minting complete.`); }); it('can get info', async () => { - const name = toString(await tokenAtWallet0.methods.private_get_name().simulate()); + const name = toString(await tokenAdminWallet.methods.private_get_name().simulate()); expect(name).toBe(TOKEN_NAME); }); @@ -167,13 +140,13 @@ describe('token transfer test', () => { expect(MINT_AMOUNT).toBe( await (await TokenContract.at(tokenAddress, w)).methods.balance_of_private(w.getAddress()).simulate(), ); - expect(MINT_AMOUNT).toBe(await tokenAtWallet0.methods.balance_of_public(w.getAddress()).simulate()); + expect(MINT_AMOUNT).toBe(await tokenAdminWallet.methods.balance_of_public(w.getAddress()).simulate()); }); expect(0n).toBe( await (await TokenContract.at(tokenAddress, recipientWallet)).methods.balance_of_private(recipient).simulate(), ); - expect(0n).toBe(await tokenAtWallet0.methods.balance_of_public(recipient).simulate()); + expect(0n).toBe(await tokenAdminWallet.methods.balance_of_public(recipient).simulate()); // For each round, make both private and public transfers for (let i = 1n; i <= ROUNDS; i++) { @@ -198,7 +171,7 @@ describe('token transfer test', () => { await (await TokenContract.at(tokenAddress, w)).methods.balance_of_private(w.getAddress()).simulate(), ); expect(MINT_AMOUNT - ROUNDS * transferAmount).toBe( - await tokenAtWallet0.methods.balance_of_public(w.getAddress()).simulate(), + await tokenAdminWallet.methods.balance_of_public(w.getAddress()).simulate(), ); }); @@ -206,7 +179,7 @@ describe('token transfer test', () => { await (await TokenContract.at(tokenAddress, recipientWallet)).methods.balance_of_private(recipient).simulate(), ); expect(ROUNDS * transferAmount * BigInt(wallets.length)).toBe( - await tokenAtWallet0.methods.balance_of_public(recipient).simulate(), + await tokenAdminWallet.methods.balance_of_public(recipient).simulate(), ); }); }); From 4a4b500f2443eaf2e1179d231dbf74f16cb53933 Mon Sep 17 00:00:00 2001 From: Mitch Date: Sat, 7 Sep 2024 20:21:37 -0400 Subject: [PATCH 7/8] increase transfer test timeout and parallelization --- .../end-to-end/src/spartan/transfer.test.ts | 56 +++++++++++-------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/yarn-project/end-to-end/src/spartan/transfer.test.ts b/yarn-project/end-to-end/src/spartan/transfer.test.ts index a472218d3d5..704b333d5eb 100644 --- a/yarn-project/end-to-end/src/spartan/transfer.test.ts +++ b/yarn-project/end-to-end/src/spartan/transfer.test.ts @@ -34,7 +34,7 @@ const toString = ({ value }: { value: bigint }) => { }; describe('token transfer test', () => { - jest.setTimeout(10 * 60 * 1000); // 10 minutes + jest.setTimeout(10 * 60 * 2000); // 20 minutes const logger = createDebugLogger(`aztec:spartan-test:transfer`); const TOKEN_NAME = 'USDC'; @@ -42,7 +42,7 @@ describe('token transfer test', () => { const TOKEN_DECIMALS = 18n; const MINT_AMOUNT = 20n; - const WALLET_COUNT = 1; + const WALLET_COUNT = 16; const ROUNDS = 5n; let pxe: PXE; @@ -101,28 +101,40 @@ describe('token transfer test', () => { logger.verbose(`Minting ${MINT_AMOUNT} private assets to the ${wallets.length} wallets...`); - for (const wallet of wallets) { - const walletAddress = wallet.getAddress(); - const mintSecret = Fr.random(); - const mintSecretHash = computeSecretHash(mintSecret); - - const tx = await tokenAdminWallet.methods.mint_private(MINT_AMOUNT, mintSecretHash).send().wait({ timeout: 600 }); - - const note = new Note([new Fr(MINT_AMOUNT), mintSecretHash]); - const extendedNote = new ExtendedNote( - note, - walletAddress, - tokenAddress, - TokenContract.storage.pending_shields.slot, - TokenContract.notes.TransparentNote.id, - tx.txHash, - ); - await pxe.addNote(extendedNote, walletAddress); + const mintSecrets = Array.from({ length: WALLET_COUNT }) + .map(() => Fr.random()) + .map(secret => ({ + secret, + hash: computeSecretHash(secret), + })); + + const txs = await Promise.all( + mintSecrets.map(({ hash }) => + tokenAdminWallet.methods.mint_private(MINT_AMOUNT, hash).send().wait({ timeout: 600 }), + ), + ); - const token = await TokenContract.at(tokenAddress, wallet); + logger.verbose(`Redeeming private assets...`); - await token.methods.redeem_shield(walletAddress, MINT_AMOUNT, mintSecret).send().wait({ timeout: 600 }); - } + await Promise.all( + mintSecrets.map(async ({ secret, hash }, i) => { + const wallet = wallets[i]; + const walletAddress = wallet.getAddress(); + const note = new Note([new Fr(MINT_AMOUNT), hash]); + const extendedNote = new ExtendedNote( + note, + walletAddress, + tokenAddress, + TokenContract.storage.pending_shields.slot, + TokenContract.notes.TransparentNote.id, + txs[i].txHash, + ); + + await pxe.addNote(extendedNote, walletAddress); + const token = await TokenContract.at(tokenAddress, wallet); + await token.methods.redeem_shield(walletAddress, MINT_AMOUNT, secret).send().wait({ timeout: 600 }); + }), + ); logger.verbose(`Minting complete.`); }); From 133131bbfa2f7fe21f9bb8bae955c50aa1a1f141 Mon Sep 17 00:00:00 2001 From: Mitch Date: Sat, 7 Sep 2024 20:58:38 -0400 Subject: [PATCH 8/8] more logging --- spartan/aztec-network/templates/pxe.deployment.yaml | 4 ++++ spartan/aztec-network/templates/tests/run-tests.yaml | 6 ++++++ spartan/aztec-network/values.yaml | 2 ++ 3 files changed, 12 insertions(+) diff --git a/spartan/aztec-network/templates/pxe.deployment.yaml b/spartan/aztec-network/templates/pxe.deployment.yaml index d4a2aa1af6d..f664837fbd1 100644 --- a/spartan/aztec-network/templates/pxe.deployment.yaml +++ b/spartan/aztec-network/templates/pxe.deployment.yaml @@ -31,6 +31,10 @@ spec: value: {{ include "aztec-network.bootNodeUrl" . | quote }} - name: LOG_JSON value: "1" + - name: LOG_LEVEL + value: "{{ .Values.pxe.logLevel }}" + - name: DEBUG + value: "{{ .Values.pxe.debug }}" ports: - name: http containerPort: {{ .Values.pxe.service.port }} diff --git a/spartan/aztec-network/templates/tests/run-tests.yaml b/spartan/aztec-network/templates/tests/run-tests.yaml index 2608b24ffbe..bc32cfd7b00 100644 --- a/spartan/aztec-network/templates/tests/run-tests.yaml +++ b/spartan/aztec-network/templates/tests/run-tests.yaml @@ -17,3 +17,9 @@ spec: value: {{ .Values.scenario }} - name: PXE_URL value: {{ include "aztec-network.pxeUrl" . | quote }} + - name: DEBUG + value: "aztec:*" + - name: LOG_LEVEL + value: "debug" + - name: LOG_JSON + value: "1" diff --git a/spartan/aztec-network/values.yaml b/spartan/aztec-network/values.yaml index 13acf19ddbe..1d2650fdf73 100644 --- a/spartan/aztec-network/values.yaml +++ b/spartan/aztec-network/values.yaml @@ -67,6 +67,8 @@ proverNode: resources: {} pxe: + logLevel: "debug" + debug: "aztec:*" replicas: 1 service: type: ClusterIP