---
AWSTemplateFormatVersion: '2010-09-09'
Description: >
  This template creates an Ethereum network on an Amazon ECS cluster or Amazon EC2 instance.
  It also includes the Ethereum Network Stats and Ethereum Explorer services.
  Additional components may be deployed depending on the container platform chosen.
  License: Apache 2.0 (Please do not remove) Apr 4, 2018 (bt-f5kb4kx9v)

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Ethereum network parameters
        Parameters:
          - NetworkID
          - GasPriceFloor
          - EthereumNodeLogLevel
          - BlockGasLimit

      - Label:
          default: Private Ethereum network parameters
        Parameters:
          - InitialDifficulty
          - InitialAccountAddresses
          - InitialAccountBalance
          - MinerAccountAddress
          - InitialBlockGasLimit

      - Label:
          default: Platform configuration
        Parameters:
          - ContainerPlatform
          - EC2InstanceType

      - Label:
          default: EC2 configuration
        Parameters:
          - EC2KeyPairName
          - EC2SecurityGroup
          - EC2InstanceProfileArn

      - Label:
          default: VPC network configuration
        Parameters:
          - VPCID
          - NetworkSubnetIDs

      - Label:
          default: ECS cluster configuration
        Parameters:
          - NumberOfEC2Instances
          - NumberOfEthereumClients
          - NumberOfEthereumMiners

      - Label:
          default: Application Load Balancer configuration (ECS only)
        Parameters:
          - ALBSubnetIDs
          - LoadBalancerSecurityGroup
          - ECSRoleForALB

      - Label:
          default: EthStats
        Parameters:
          - RunEthStats
          - EthStatsSecret

      - Label:
          default: EthExplorer
        Parameters:
          - RunEthExplorer

    ParameterLabels:
      NetworkSubnetIDs:
        default: Ethereum Network Subnet IDs
      NumberOfEthereumClients:
        default: Number of Ethereum Clients
      NumberOfEthereumMiners:
        default: Number of Ethereum Miners
      InitialAccountAddresses:
        default: Initial List of Accounts
      NetworkID:
        default: Ethereum Network ID
      MinerAccountAddress:
        default: Miner Account Address
      BlockGasLimit:
        default: Target Block Gas Limit
      InitialBlockGasLimit:
        default: Initial Block Gas Limit
      EthereumNodeLogLevel:
        default: Ethereum Node Log Level
      EC2KeyPairName:
        default: EC2 Key Pair
      EC2SecurityGroup:
        default: EC2 Security Group
      ECSRoleForALB:
        default: IAM Role
      RunEthExplorer:
        default: Deploy EthExplorer
      RunEthStats:
        default: Deploy EthStats
      NumberOfEC2Instances:
        default: EC2 Instance Count for ECS
      EC2InstanceType:
        default: EC2 Instance Type
      EC2InstanceProfileArn:
        default: EC2 Instance Profile ARN
      ContainerPlatform:
        default: Container Platform
      GasPriceFloor:
        default: Gas Price Floor
      InitialAccountBalance:
        default: Initial Account Balance
      EthStatsSecret:
        default: EthStats Connection Secret
      NestedTemplateOrigin:
        default: Nested Template S3 URL Prefix
      ALBSubnetIDs:
        default: Application Load Balancer Subnet IDs
      VPCID:
        default: VPC ID
      InitialDifficulty:
        default: Initial Mining Difficulty
      LoadBalancerSecurityGroup:
        default: Application Load Balancer Security Group

Parameters:
  VPCID:
    Description: The ID of the VPC into which to launch the stack resources.
    Type: AWS::EC2::VPC::Id
  NetworkSubnetIDs:
    Description: The ID of one or more subnets into which the Ethereum network is launched. Subnets can be public or private but cannot be mixed. We recommend private subnets.
    Type: List<AWS::EC2::Subnet::Id>
  ALBSubnetIDs:
    Description: The IDs of at least two subnets into which the Application Load Balancer is launched. These should be in different Availability Zones.
    Type: List<AWS::EC2::Subnet::Id>
    MinLength: 2
  NumberOfEthereumClients:
    Type: Number
    Default: '2'
    MinValue: 1
    MaxValue: 20
    Description: There must be at least one Ethereum client.
    ConstraintDescription: You must have at least one Ethereum client.
  NumberOfEthereumMiners:
    Type: Number
    Default: '1'
    MinValue: 0
    MaxValue: 20
    Description: Miners are optional. For private networks, you should start at least 1 miner.
  InitialAccountAddresses:
    Type: String
    Default: "0x0ADfCCa4B2a1132F82488546AcA086D7E24EA324,0x0bd5EebDC3E53973dDF236D43906C776a5fE3784,0x9537cb86f5a03C8CCB52c44b49757861eCA0004b,0x1Fbc353788338F902630E5494aD7FaC7dF8dBb29,0x5ccBe3B9B15eFB62bB2696051091Ee7C1Eb4c7E6"
    Description: A comma-separated list of account addresses that are funded when the private network starts.
    AllowedPattern: "^(0x[a-fA-F0-9]{40})(,0x[a-fA-F0-9]{40})*$"
  InitialAccountBalance:
    Type: Number
    Default: '1000'
    Description: The starting balance in ether for each of the initial accounts.
    MinValue: 0
  MinerAccountAddress:
    Type: String
    Default: '0x0ADfCCa4B2a1132F82488546AcA086D7E24EA324'
    Description: The account address to which newly mined ether is awarded.
    AllowedPattern: "^(0x[a-fA-F0-9]{40})$"
  InitialDifficulty:
    Type: Number
    Default: "1"
    MinValue: 1
    Description: If you set this higher than 1, the miner may not be able to mine blocks.
    ConstraintDescription: Must enter an initial difficulty greater than or equal to 1.
  NetworkID:
    Type: Number
    Description: The ID of the Ethereum network. An ID between 1 and 4 specifies public Ethereum networks. Public networks do not require private Ethereum network parameters, which are used in the genesis block.
    Default: '1234'
    MinValue: 1
    MaxValue: 100000
    ConstraintDescription: The ID of the network must be between 1 and 100000.
  BlockGasLimit:
    Type: Number
    Default: '8000000'
    Description: The limit on the total amount of gas that can be spent for transactions in a block. This is the target block gas limit for the miner, not the starting block gas limit set in the genesis block.
    MinValue: 1000000
    MaxValue: 1000000000
    ConstraintDescription: Block Gas Limit must be between 1 million and 1 billion.
  InitialBlockGasLimit:
    Type: Number
    Default: '8000000'
    Description: The initial limit on the total amount of gas that can be spent for transactions in a block. This is the starting block gas limit set in the genesis block, not the target block gas limit for the miner.
    MinValue: 1000000
    MaxValue: 1000000000
    ConstraintDescription: Block Gas Limit must be between 1 million and 1 billion.
  GasPriceFloor:
    Type: Number
    Default: '0'
    Description: The minimum gas price for a transaction that the miners accept to include a transaction in a block in WEI.
    MinValue: 0
    MaxValue: 1000000000000
    ConstraintDescription: You shouldn't set this to more than 1000 GWEI.
  RunEthExplorer:
    Type: String
    AllowedValues:
      - "true"
      - "false"
    Default: "true"
  RunEthStats:
    Type: String
    AllowedValues:
      - "true"
      - "false"
    Default: "true"
  EC2InstanceProfileArn:
    Type: String
    Description: The ARN of the role to associate with EC2 instances in the stack. The role must have permissions to write to the Amazon DynamoDB peer table.
  EC2KeyPairName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: The name of an existing EC2 key pair to enable access to EC2 instances in the stack.
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup::Id
    Description: The name of an existing security group to assign to EC2 instances.
  LoadBalancerSecurityGroup:
    Type: AWS::EC2::SecurityGroup::Id
    Description: The name of an existing security group to assign to the Application Load Balancer in the stack.
  ECSRoleForALB:
    Type: String
    Description: The ARN of the role that ECS uses to interact with Application Load Balancers.
  ContainerPlatform:
    Type: String
    Default: ecs
    AllowedValues:
      - ecs
      - docker-local
    Description: The container orchestration platform.
  NumberOfEC2Instances:
    Type: Number
    Default: '3'
    Description: The total number of EC2 instances to launch for ECS. This must equal the sum of Ethereum clients and miners.
  EC2InstanceType:
    Type: String
    Default: t2.medium
    AllowedValues:
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
      - t2.xlarge
      - t2.2xlarge
      - m3.medium
      - m3.large
      - m3.xlarge
      - m3.2xlarge
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m4.10xlarge
      - r3.large
      - r3.xlarge
      - r3.2xlarge
      - r3.4xlarge
      - r3.8xlarge
      - r4.large
      - r4.xlarge
      - r4.2xlarge
      - r4.4xlarge
      - r4.8xlarge
      - r4.16xlarge
      - c4.large
      - c4.xlarge
      - c4.2xlarge
      - c4.4xlarge
      - c4.8xlarge
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
      - c5.9xlarge
      - c5.18xlarge
    ConstraintDescription: Please choose a valid instance type.
  EthStatsSecret:
    Type: String
    Default: "duplo12345"
    NoEcho: true
    MinLength: 6
    MaxLength: 16
    ConstraintDescription: Secret must be between 6 and 16 characters.
  EthereumNodeLogLevel:
    Type: String
    Default: "info"
    AllowedValues:
      - "trace"
      - "debug"
      - "info"
      - "warn"
      - "error"
      - "fatal"
    Description: "The log level of the Ethereum node"

  NestedTemplateOrigin:
    Type: String
    Description: The prefix of the Amazon S3 URL where the nested CloudFormation templates are stored.
    AllowedPattern: "^https?://.+/$"
    ConstraintDescription: "Must start with 'http://' or 'https://' and end with a '/' character."
    Default: https://aws-blockchain-templates-us-east-1.s3.amazonaws.com/ethereum/templates/latest/templates/

Mappings:
  RegionToResourceRegion:
    us-east-1:
      to: us-east-1
    us-east-2:
      to: us-east-2
    us-west-2:
      to: us-west-2
    us-west-1:
      to: us-west-2
    ca-central-1:
      to: us-east-1
    eu-central-1:
      to: us-east-1
    eu-west-1:
      to: us-east-1
    eu-west-2:
      to: us-east-1
    eu-west-3:
      to: us-east-1
    ap-northeast-2:
      to: us-east-1
    ap-northeast-1:
      to: us-east-1
    ap-southeast-2:
      to: us-east-1
    ap-southeast-1:
      to: us-east-1
    sa-east-1:
      to: us-east-1
    ap-south-1:
      to: us-east-1

  RegionInformationMap:
    us-east-1:
      ResourceAccountId: 354658284331
    us-east-2:
      ResourceAccountId: 763976151875
    us-west-2:
      ResourceAccountId: 712425161857

Resources:
  EthereumCommonStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub "${NestedTemplateOrigin}ethereum-common.template.yaml"
      Parameters:
        VPCID:
          Ref: VPCID
        NetworkSubnetIDs:
          Fn::Join:
            - ","
            - Ref: NetworkSubnetIDs
        ALBSubnetIDs:
          Fn::Join:
            - ","
            - Ref: ALBSubnetIDs
        NumberOfEthereumClients:
          Ref: NumberOfEthereumClients
        NumberOfEthereumMiners:
          Ref: NumberOfEthereumMiners
        InitialAccountAddresses:
          Ref: InitialAccountAddresses
        NetworkID:
          Ref: NetworkID
        BlockGasLimit:
          Ref: BlockGasLimit
        InitialBlockGasLimit:
          Ref: InitialBlockGasLimit
        EC2InstanceProfileArn:
          Ref: EC2InstanceProfileArn
        EC2KeyPairName:
          Ref: EC2KeyPairName
        EC2SecurityGroup:
          Ref: EC2SecurityGroup
        ECSRoleForALB:
          Ref: ECSRoleForALB
        NumberOfEC2Instances:
          Ref: NumberOfEC2Instances
        EC2InstanceType:
          Ref: EC2InstanceType
        RootStackName:
          Ref: AWS::StackName
        MinerAccountAddress:
          Ref: MinerAccountAddress
        EthereumNodeLogLevel:
          Ref: EthereumNodeLogLevel
        RunEthExplorer:
          Ref: RunEthExplorer
        RunEthStats:
          Ref: RunEthStats
        EthStatsSecret:
          Ref: EthStatsSecret
        ContainerPlatform:
          Ref: ContainerPlatform
        InitialDifficulty:
          Ref: InitialDifficulty
        InitialAccountBalance:
          Ref: InitialAccountBalance
        GasPriceFloor:
          Ref: GasPriceFloor
        LoadBalancerSecurityGroup:
          Ref: LoadBalancerSecurityGroup
        ClusterName:
          Fn::Sub: "${AWS::StackName}-Ethereum"
        DockerRegion:
          Fn::FindInMap:
            - RegionToResourceRegion
            - Ref: AWS::Region
            - to
        DockerECRAccount:
          Fn::FindInMap:
            - RegionInformationMap
            - Fn::FindInMap:
              - RegionToResourceRegion
              - Ref: AWS::Region
              - to
            - ResourceAccountId
        EthereumDockerImage:
          Fn::Sub:
            - "${DockerECRAccount}.dkr.ecr.${DockerRegion}.amazonaws.com/client-go:v1"
            - DockerRegion:
                Fn::FindInMap:
                  - RegionToResourceRegion
                  - Ref: AWS::Region
                  - to
              DockerECRAccount:
                Fn::FindInMap:
                  - RegionInformationMap
                  - Fn::FindInMap:
                    - RegionToResourceRegion
                    - Ref: AWS::Region
                    - to
                  - ResourceAccountId
        EthStatsDockerImage:
          Fn::Sub:
            - "${DockerECRAccount}.dkr.ecr.${DockerRegion}.amazonaws.com/eth-netstats:v1"
            - DockerRegion:
                Fn::FindInMap:
                  - RegionToResourceRegion
                  - Ref: AWS::Region
                  - to
              DockerECRAccount:
                Fn::FindInMap:
                  - RegionInformationMap
                  - Fn::FindInMap:
                    - RegionToResourceRegion
                    - Ref: AWS::Region
                    - to
                  - ResourceAccountId
        EthExplorerDockerImage:
          Fn::Sub:
            - "${DockerECRAccount}.dkr.ecr.${DockerRegion}.amazonaws.com/eth-explorer:v1"
            - DockerRegion:
                Fn::FindInMap:
                  - RegionToResourceRegion
                  - Ref: AWS::Region
                  - to
              DockerECRAccount:
                Fn::FindInMap:
                  - RegionInformationMap
                  - Fn::FindInMap:
                    - RegionToResourceRegion
                    - Ref: AWS::Region
                    - to
                  - ResourceAccountId
        NestedTemplateOrigin: !Ref NestedTemplateOrigin

Outputs:
  EthStatsURL:
    Description: "Visit this URL to see the status of your Ethereum nodes"
    Value:
      Fn::GetAtt: ["EthereumCommonStack", "Outputs.EthStatsURL"]
  EthExplorerURL:
    Description: "Visit this URL to view transactions on your Ethereum network"
    Value:
      Fn::GetAtt: ["EthereumCommonStack", "Outputs.EthExplorerURL"]
  EthJsonRPCURL:
    Description: "Use this URL to access the Geth JSON RPC of your Ethereum Clients, or input it into Metamask"
    Value:
      Fn::GetAtt: ["EthereumCommonStack", "Outputs.EthJsonRPCURL"]