diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml index 0cda6f3e3..60d50d2f6 100644 --- a/.github/workflows/docker-build.yaml +++ b/.github/workflows/docker-build.yaml @@ -5,21 +5,20 @@ on: tags: - v* push: - branches: [ netmarble_v1.0 ] + branches: [ netmarble_v1.0, netmarble_v2.0 ] pull_request: - branches: [ netmarble_v1.0 ] + branches: [ netmarble_v1.0, netmarble_v2.0 ] env: REGION: us-east-1 ECR_REGISTRY_ID: 553885929720 - AWS_ASSUMED_ROLE_ARN: arn:aws:iam::553885929720:role/tf_nodereal_prod_ecr_cicd_deployment_assume_role # Notice: must modify here to fit your service config path GIT_SYNC_PATH: qa/gitops/qa-us/demo-app/values.yaml TAG_FIELD: .image.tag jobs: CI: - runs-on: [self-hosted,qa-infra-k8s] + runs-on: [self-hosted,prod-cicd-runners] steps: - uses: actions/checkout@v3 # - uses: actions/setup-go@v3 @@ -30,23 +29,9 @@ jobs: # with: # # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version # version: v1.45.2 - - name: aws assume role - id: aws-assume-role - run: | - UUID=$(cat /proc/sys/kernel/random/uuid) - OUT=$(aws sts assume-role --role-arn $AWS_ASSUMED_ROLE_ARN --role-session-name $UUID) - echo ::set-output name=aws_access_key_id::"$(echo $OUT | jq -r '.Credentials''.AccessKeyId')" - echo ::set-output name=aws_secret_key::"$(echo $OUT | jq -r '.Credentials''.SecretAccessKey')" - echo ::set-output name=aws_sessions_token::"$(echo $OUT | jq -r '.Credentials''.SessionToken')" - name: Build, tag, and push image to Amazon ECR - env: - AWS_ACCESS_KEY_ID: ${{ steps.aws-assume-role.outputs.aws_access_key_id }} - AWS_SECRET_ACCESS_KEY: ${{ steps.aws-assume-role.outputs.aws_secret_key }} - AWS_SESSION_TOKEN: ${{ steps.aws-assume-role.outputs.aws_sessions_token }} run: | aws ecr get-login-password --region ${REGION} | docker login --username AWS --password-stdin ${ECR_REGISTRY_ID}.dkr.ecr.${REGION}.amazonaws.com - aws ecr --region $REGION describe-repositories --registry-id $ECR_REGISTRY_ID --repository-names ${GITHUB_REPOSITORY#*/} || aws ecr --region $REGION create-repository --registry-id $ECR_REGISTRY_ID --repository-name ${GITHUB_REPOSITORY#*/} - aws ecr --region $REGION set-repository-policy --registry-id $ECR_REGISTRY_ID --repository-name ${GITHUB_REPOSITORY#*/} --policy-text file:///home/runner/repo-access-permissions.json docker build -t ${ECR_REGISTRY_ID}.dkr.ecr.${REGION}.amazonaws.com/${GITHUB_REPOSITORY#*/}:${GITHUB_SHA} . docker push ${ECR_REGISTRY_ID}.dkr.ecr.${REGION}.amazonaws.com/${GITHUB_REPOSITORY#*/}:${GITHUB_SHA} # CD: diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 47d333fed..1c37e00c4 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -311,6 +311,14 @@ func geth(ctx *cli.Context) error { defer stack.Close() startNode(ctx, stack, backend) + + log.Info("***************************** CONFIG INFO ****************************") + log.Info("******* FNCY_2.0", "chainId", backend.ChainConfig().ChainID) + log.Info("******* FNCY_2.0", "contract48kBlock", backend.ChainConfig().Contract48kBlock.Int64()) + log.Info("******* FNCY_2.0", "fncy2Block", backend.ChainConfig().Fncy2Block.Int64()) + log.Info("******* FNCY_2.0", "stopMintBlock", backend.ChainConfig().Parlia.StopMintBlock.Int64()) + log.Info("***************************** CONFIG INFO *****************************") + log.Info("Start FNCY_2.0 success") stack.Wait() return nil } diff --git a/consensus/parlia/abi.go b/consensus/parlia/abi.go index a0b49800c..7c0817b8b 100644 --- a/consensus/parlia/abi.go +++ b/consensus/parlia/abi.go @@ -2,544 +2,1051 @@ package parlia const validatorSetABI = ` [ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "batchTransfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "validator", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "deprecatedDeposit", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address payable", - "name": "validator", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "directTransfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "systemTransfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "validator", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "validatorDeposit", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "validator", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "validatorFelony", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "validator", - "type": "address" - } - ], - "name": "validatorJailed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "validator", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "validatorMisdemeanor", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "validatorSetUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "CHANNEL_ID", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "DUSTY_INCOMING", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "EXTRA_FEE", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "JAIL_MESSAGE_TYPE", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "RELAYER_REWARD", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "SYSTEM_ADDRESS", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "VALIDATORS_UPDATE_MESSAGE_TYPE", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "alreadyInit", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "currentValidatorSet", - "outputs": [ - { - "internalType": "address", - "name": "consensusAddress", - "type": "address" - }, - { - "internalType": "address payable", - "name": "feeAddress", - "type": "address" - }, - { - "internalType": "address", - "name": "BBCFeeAddress", - "type": "address" - }, - { - "internalType": "uint64", - "name": "votingPower", - "type": "uint64" - }, - { - "internalType": "bool", - "name": "jailed", - "type": "bool" - }, - { - "internalType": "uint256", - "name": "incoming", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "fromChainId", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "initLightClientAddr", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "initSlashContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "initSystemRewardAddr", - "outputs": [ - { - "internalType": "address payable", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "initTokenHubAddr", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "initValidatorSetBytes", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "keyPrefix", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "previousDepositHeight", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "sequence", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "toChainId", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalInComing", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "init", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "valAddr", - "type": "address" - } - ], - "name": "deposit", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "msgBytes", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "proof", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "height", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "packageSequence", - "type": "uint64" - } - ], - "name": "update", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "getValidators", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validator", - "type": "address" - } - ], - "name": "getIncoming", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validator", - "type": "address" - } - ], - "name": "misdemeanor", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "validator", - "type": "address" - } - ], - "name": "felony", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ] + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "epoch", + "type": "uint64" + } + ], + "name": "Claimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "epoch", + "type": "uint64" + } + ], + "name": "Delegated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dust", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "epoch", + "type": "uint64" + } + ], + "name": "Redelegated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ShareRewards", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "epoch", + "type": "uint64" + } + ], + "name": "Undelegated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "status", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "commissionRate", + "type": "uint16" + } + ], + "name": "ValidatorAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "epoch", + "type": "uint64" + } + ], + "name": "ValidatorDeposited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "epoch", + "type": "uint64" + } + ], + "name": "ValidatorJailed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "status", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "commissionRate", + "type": "uint16" + } + ], + "name": "ValidatorModified", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "epoch", + "type": "uint64" + } + ], + "name": "ValidatorOwnerClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "epoch", + "type": "uint64" + } + ], + "name": "ValidatorReleased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "ValidatorRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "slashes", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "epoch", + "type": "uint64" + } + ], + "name": "ValidatorSlashed", + "type": "event" + }, + { + "inputs": [], + "name": "init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "delayedInitializer", + "type": "bytes" + } + ], + "name": "useDelayedInitializer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "validators", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "owners", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "initialStakes", + "type": "uint256[]" + }, + { + "internalType": "uint16", + "name": "commissionRate", + "type": "uint16" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "delegator", + "type": "address" + } + ], + "name": "getValidatorDelegation", + "outputs": [ + { + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "atEpoch", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "getValidatorStatus", + "outputs": [ + { + "internalType": "address", + "name": "ownerAddress", + "type": "address" + }, + { + "internalType": "uint8", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "totalDelegated", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "slashesCount", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "changedAt", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "jailedBefore", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "claimedAt", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "commissionRate", + "type": "uint16" + }, + { + "internalType": "uint96", + "name": "totalRewards", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + }, + { + "internalType": "uint64", + "name": "epoch", + "type": "uint64" + } + ], + "name": "getValidatorStatusAtEpoch", + "outputs": [ + { + "internalType": "address", + "name": "ownerAddress", + "type": "address" + }, + { + "internalType": "uint8", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "totalDelegated", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "slashesCount", + "type": "uint32" + }, + { + "internalType": "uint64", + "name": "changedAt", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "jailedBefore", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "claimedAt", + "type": "uint64" + }, + { + "internalType": "uint16", + "name": "commissionRate", + "type": "uint16" + }, + { + "internalType": "uint96", + "name": "totalRewards", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "getValidatorByOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "releaseValidatorFromJail", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "forceUnJailValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "delegate", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "undelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "currentEpoch", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nextEpoch", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + }, + { + "internalType": "uint16", + "name": "commissionRate", + "type": "uint16" + } + ], + "name": "registerValidator", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "removeValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "activateValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "disableValidator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + }, + { + "internalType": "uint16", + "name": "commissionRate", + "type": "uint16" + } + ], + "name": "changeValidatorCommissionRate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "changeValidatorOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isValidatorActive", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "isValidator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getValidators", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "blockRewards", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasFee", + "type": "uint256" + } + ], + "name": "distributeRewards", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "getValidatorFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "getPendingValidatorFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "claimValidatorFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "delegatorAddress", + "type": "address" + } + ], + "name": "getDelegatorFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "delegatorAddress", + "type": "address" + } + ], + "name": "getPendingDelegatorFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "claimDelegatorFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "claimPendingUndelegates", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "internalType": "address", + "name": "delegator", + "type": "address" + } + ], + "name": "calcAvailableForRedelegateAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToStake", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardsDust", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "redelegateDelegatorFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "validatorAddress", + "type": "address" + } + ], + "name": "slash", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] ` const slashABI = ` diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 9cb505e2e..9db67a943 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -1054,6 +1054,9 @@ func (p *Parlia) getCurrentValidators(blockHash common.Hash) ([]common.Address, } func (p *Parlia) BlockRewards(blockNumber *big.Int) *big.Int { if rules := p.chainConfig.Rules(blockNumber); rules.HasBlockRewards { + if p.chainConfig.Parlia.StopMintBlock != nil && p.chainConfig.Parlia.StopMintBlock.Cmp(blockNumber) <= 0 { + return nil + } blockRewards := p.chainConfig.Parlia.BlockRewards if blockRewards != nil && blockRewards.Cmp(common.Big0) > 0 { return blockRewards @@ -1070,17 +1073,21 @@ func (p *Parlia) distributeIncoming(val common.Address, state *state.StateDB, he state.SetBalance(consensus.SystemAddress, big.NewInt(0)) state.AddBalance(coinbase, balance) rewards := big.NewInt(0).Abs(balance) - if rules := p.chainConfig.Rules(header.Number); rules.HasBlockRewards { - blockRewards := p.chainConfig.Parlia.BlockRewards - // if we have enabled block rewards and rewards are greater than 0 then - if blockRewards != nil && blockRewards.Cmp(common.Big0) > 0 { - state.AddBalance(coinbase, blockRewards) - rewards = rewards.Add(rewards, blockRewards) - } + blockRewards := p.BlockRewards(header.Number) + if blockRewards != nil { + rewards = rewards.Add(rewards, blockRewards) + state.AddBalance(coinbase, blockRewards) } if rewards.Cmp(common.Big0) <= 0 { return nil } + if p.chainConfig.IsFncy2(header.Number) { + if blockRewards == nil { + blockRewards = big.NewInt(0) + } + log.Trace("fncy2 distribute to validator contract", "block hash", header.Hash(), "amount", rewards) + return p.distributeRewards(rewards, blockRewards, balance, val, state, header, chain, txs, receipts, receivedTxs, usedGas, mining) + } // remove 1/16 reward according to netmarble //doDistributeSysReward := state.GetBalance(common.HexToAddress(systemcontract.SystemRewardContract)).Cmp(maxSystemBalance) < 0 //if doDistributeSysReward { @@ -1160,6 +1167,27 @@ func (p *Parlia) distributeToSystem(amount *big.Int, state *state.StateDB, heade return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining) } +// slash spoiled validators +func (p *Parlia) distributeRewards(amount *big.Int, blockRewards *big.Int, gasFee *big.Int, validator common.Address, + state *state.StateDB, header *types.Header, chain core.ChainContext, + txs *[]*types.Transaction, receipts *[]*types.Receipt, receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool) error { + // method + method := "distributeRewards" + + // get packed data + data, err := p.validatorSetABI.Pack(method, + validator, blockRewards, gasFee, + ) + if err != nil { + log.Error("Unable to pack tx for distributeRewards", "error", err) + return err + } + // get system message + msg := p.getSystemMessage(header.Coinbase, common.HexToAddress(systemcontract.ValidatorContract), data, amount) + // apply message + return p.applyTransaction(msg, state, header, chain, txs, receipts, receivedTxs, usedGas, mining) +} + // slash spoiled validators func (p *Parlia) distributeToValidator(amount *big.Int, validator common.Address, state *state.StateDB, header *types.Header, chain core.ChainContext, diff --git a/core/state_transition.go b/core/state_transition.go index e71b98075..636c90636 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -39,8 +39,10 @@ The state transitioning model does all the necessary work to work out a valid ne 3) Create a new state object if the recipient is \0*32 4) Value transfer == If contract creation == - 4a) Attempt to run transaction data - 4b) If valid, use result as code for the new state object + + 4a) Attempt to run transaction data + 4b) If valid, use result as code for the new state object + == end == 5) Run Script section 6) Derive new state root @@ -213,13 +215,13 @@ func (st *StateTransition) preCheck() error { // TransitionDb will transition the state by applying the current message and // returning the evm execution result with following fields. // -// - used gas: -// total gas used (including gas being refunded) -// - returndata: -// the returned data from evm -// - concrete execution error: -// various **EVM** error which aborts the execution, -// e.g. ErrOutOfGas, ErrExecutionReverted +// - used gas: +// total gas used (including gas being refunded) +// - returndata: +// the returned data from evm +// - concrete execution error: +// various **EVM** error which aborts the execution, +// e.g. ErrOutOfGas, ErrExecutionReverted // // However if any consensus issue encountered, return the error directly with // nil evm execution result. @@ -238,6 +240,14 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { if err := st.preCheck(); err != nil { return nil, err } + + if st.evm.VmConfig.Debug { + st.evm.VmConfig.Tracer.CaptureTxStart(st.initialGas) + defer func() { + st.evm.VmConfig.Tracer.CaptureTxEnd(st.gas) + }() + } + msg := st.msg sender := vm.AccountRef(msg.From()) homestead := st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber) diff --git a/core/tx_pool.go b/core/tx_pool.go index ba073a29a..954c75cb1 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -253,6 +253,7 @@ type TxPool struct { gasFreeAddressMap map[common.Address]uint // from address that can join tx_pool for free gasFreeAddressMapFunc func(common.Hash) (map[common.Address]uint, error) // add func to get gasFreeAddressMap + gasPriceFunc func(common.Hash) (*big.Int, error) // add func to get gas price, do nothing when return 0 pending map[common.Address]*txList // All currently processable transactions queue map[common.Address]*txList // Queued but non-processable transactions @@ -283,11 +284,17 @@ func getNoGasFreeAddressMapFunc() func(common.Hash) (map[common.Address]uint, er return gasFreeToAddressMap, nil } } +func getGasPriceFunc() func(common.Hash) (*big.Int, error) { + return func(blockHash common.Hash) (*big.Int, error) { + return big.NewInt(0), nil + } +} + func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain) *TxPool { - return NewEnhanceTxPool(config, chainconfig, chain, getNoGasFreeAddressMapFunc()) + return NewEnhanceTxPool(config, chainconfig, chain, getNoGasFreeAddressMapFunc(), getGasPriceFunc()) } -func NewEnhanceTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain, gasFreeAddressMapFunc func(common.Hash) (map[common.Address]uint, error)) *TxPool { +func NewEnhanceTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain, gasFreeAddressMapFunc func(common.Hash) (map[common.Address]uint, error), gasPriceFunc func(common.Hash) (*big.Int, error)) *TxPool { // Sanitize the input to ensure no vulnerable gas prices are set config = (&config).sanitize() // Create the transaction pool with its initial settings @@ -309,6 +316,7 @@ func NewEnhanceTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chai gasPrice: new(big.Int).SetUint64(config.PriceLimit), gasFreeAddressMap: make(map[common.Address]uint), gasFreeAddressMapFunc: gasFreeAddressMapFunc, + gasPriceFunc: gasPriceFunc, } pool.locals = newAccountSet(pool.signer) for _, addr := range config.Locals { @@ -479,10 +487,19 @@ func (pool *TxPool) SubscribeReannoTxsEvent(ch chan<- ReannoTxsEvent) event.Subs func (pool *TxPool) GasPrice() *big.Int { pool.mu.RLock() defer pool.mu.RUnlock() + return new(big.Int).Set(pool.gasPrice) +} +//Fncy2 Update +func (pool *TxPool) GasPriceWithoutLock() *big.Int { return new(big.Int).Set(pool.gasPrice) } +func (pool *TxPool) SetGasPriceWithoutLock(price *big.Int) { + pool.gasPrice = price + log.Info("Transaction pool price threshold updated", "price", price) +} + // SetGasPrice updates the minimum price required by the transaction pool for a // new transaction, and drops all transactions below this threshold. func (pool *TxPool) SetGasPrice(price *big.Int) { @@ -551,7 +568,6 @@ func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { pool.mu.Lock() defer pool.mu.Unlock() - pending := make(map[common.Address]types.Transactions) for addr, list := range pool.pending { pending[addr] = list.Flatten() @@ -1293,6 +1309,21 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { next := new(big.Int).Add(newHead.Number, big.NewInt(1)) pool.istanbul = pool.chainconfig.IsIstanbul(next) pool.eip2718 = pool.chainconfig.IsBerlin(next) + //fncy2 update + if pool.chainconfig.IsFncy2(next) { + gasPrice, err := pool.gasPriceFunc(pool.chain.CurrentBlock().Hash()) + if err != nil { + log.Warn("Failed to get gasPrice", "err", err) + } else { + if gasPrice != nil && gasPrice.Cmp(common.Big0) > 0 { + if pool.gasPrice == nil || pool.gasPrice.Cmp(gasPrice) != 0 { + log.Debug("Set gasPrice ", " old gasPrice", pool.gasPrice, " new gasPrice", gasPrice) + pool.SetGasPriceWithoutLock(gasPrice) + } + } + } + } + } // promoteExecutables moves transactions that have become processable from the diff --git a/core/vm/access_list_tracer.go b/core/vm/access_list_tracer.go index d7993b4f7..3f79d6d5a 100644 --- a/core/vm/access_list_tracer.go +++ b/core/vm/access_list_tracer.go @@ -180,3 +180,12 @@ func (a *AccessListTracer) AccessList() types.AccessList { func (a *AccessListTracer) Equal(other *AccessListTracer) bool { return a.list.equal(other.list) } + +// CaptureTxStart implements the Tracer interface and is invoked at the beginning of +// transaction processing. +func (t *AccessListTracer) CaptureTxStart(gasLimit uint64) { +} + +// CaptureTxStart implements the Tracer interface and is invoked at the end of +// transaction processing. +func (t *AccessListTracer) CaptureTxEnd(restGas uint64) {} diff --git a/core/vm/evm.go b/core/vm/evm.go index e24212105..06cf98e08 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -134,7 +134,7 @@ type EVM struct { chainRules params.Rules // virtual machine configuration options used to initialise the // evm. - vmConfig Config + VmConfig Config // global (to this context) ethereum virtual machine // used throughout the execution of the tx. interpreters []Interpreter @@ -155,7 +155,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig evm.Context = blockCtx evm.TxContext = txCtx evm.StateDB = statedb - evm.vmConfig = vmConfig + evm.VmConfig = vmConfig evm.chainConfig = chainConfig evm.chainRules = chainConfig.Rules(blockCtx.BlockNumber) evm.interpreters = make([]Interpreter, 0, 1) @@ -215,7 +215,7 @@ func (evm *EVM) Interpreter() Interpreter { // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { - if evm.vmConfig.NoRecursion && evm.depth > 0 { + if evm.VmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } // Fail if we're trying to execute above the call depth limit @@ -232,13 +232,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { // Calling a non existing account, don't do anything, but ping the tracer - if evm.vmConfig.Debug { + if evm.VmConfig.Debug { if evm.depth == 0 { - evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) - evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) + evm.VmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) + evm.VmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) } else { - evm.vmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) - evm.vmConfig.Tracer.CaptureExit(ret, 0, nil) + evm.VmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) + evm.VmConfig.Tracer.CaptureExit(ret, 0, nil) } } return nil, gas, nil @@ -248,17 +248,17 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value) // Capture the tracer start/end events in debug mode - if evm.vmConfig.Debug { + if evm.VmConfig.Debug { if evm.depth == 0 { - evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) + evm.VmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters - evm.vmConfig.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err) + evm.VmConfig.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err) }(gas, time.Now()) } else { // Handle tracer events for entering and exiting a call frame - evm.vmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) + evm.VmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) defer func(startGas uint64) { - evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err) + evm.VmConfig.Tracer.CaptureExit(ret, startGas-gas, err) }(gas) } } @@ -304,7 +304,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // CallCode differs from Call in the sense that it executes the given address' // code with the caller as context. func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { - if evm.vmConfig.NoRecursion && evm.depth > 0 { + if evm.VmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } // Fail if we're trying to execute above the call depth limit @@ -321,10 +321,10 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, var snapshot = evm.StateDB.Snapshot() // Invoke tracer hooks that signal entering/exiting a call frame - if evm.vmConfig.Debug { - evm.vmConfig.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value) + if evm.VmConfig.Debug { + evm.VmConfig.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value) defer func(startGas uint64) { - evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err) + evm.VmConfig.Tracer.CaptureExit(ret, startGas-gas, err) }(gas) } @@ -355,7 +355,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // DelegateCall differs from CallCode in the sense that it executes the given address' // code with the caller as context and the caller is set to the caller of the caller. func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { - if evm.vmConfig.NoRecursion && evm.depth > 0 { + if evm.VmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } // Fail if we're trying to execute above the call depth limit @@ -365,10 +365,10 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by var snapshot = evm.StateDB.Snapshot() // Invoke tracer hooks that signal entering/exiting a call frame - if evm.vmConfig.Debug { - evm.vmConfig.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, nil) + if evm.VmConfig.Debug { + evm.VmConfig.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, nil) defer func(startGas uint64) { - evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err) + evm.VmConfig.Tracer.CaptureExit(ret, startGas-gas, err) }(gas) } @@ -397,7 +397,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // Opcodes that attempt to perform such modifications will result in exceptions // instead of performing the modifications. func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { - if evm.vmConfig.NoRecursion && evm.depth > 0 { + if evm.VmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } // Fail if we're trying to execute above the call depth limit @@ -418,10 +418,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte evm.StateDB.AddBalance(addr, big0) // Invoke tracer hooks that signal entering/exiting a call frame - if evm.vmConfig.Debug { - evm.vmConfig.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil) + if evm.VmConfig.Debug { + evm.VmConfig.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil) defer func(startGas uint64) { - evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err) + evm.VmConfig.Tracer.CaptureExit(ret, startGas-gas, err) }(gas) } @@ -498,15 +498,15 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, contract := NewContract(caller, AccountRef(address), value, gas) contract.SetCodeOptionalHash(&address, codeAndHash) - if evm.vmConfig.NoRecursion && evm.depth > 0 { + if evm.VmConfig.NoRecursion && evm.depth > 0 { return nil, address, gas, nil } - if evm.vmConfig.Debug { + if evm.VmConfig.Debug { if evm.depth == 0 { - evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value) + evm.VmConfig.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value) } else { - evm.vmConfig.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) + evm.VmConfig.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value) } } @@ -515,7 +515,11 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, ret, err := run(evm, contract, nil, false) // Check whether the max code size has been exceeded, assign err if the case. - if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize { + maxCodeSize := params.MaxCodeSize + if evm.chainRules.IsContract48kBlock { + maxCodeSize = params.MaxCodeSize * 2 + } + if err == nil && evm.chainRules.IsEIP158 && len(ret) > maxCodeSize { err = ErrMaxCodeSizeExceeded } @@ -542,11 +546,11 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } } - if evm.vmConfig.Debug { + if evm.VmConfig.Debug { if evm.depth == 0 { - evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) + evm.VmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) } else { - evm.vmConfig.Tracer.CaptureExit(ret, gas-contract.Gas, err) + evm.VmConfig.Tracer.CaptureExit(ret, gas-contract.Gas, err) } } return ret, address, contract.Gas, err diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 0ecf28d59..68571ebd4 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -244,7 +244,7 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt interpreter.hasher.Read(interpreter.hasherBuf[:]) evm := interpreter.evm - if evm.vmConfig.EnablePreimageRecording { + if evm.VmConfig.EnablePreimageRecording { evm.StateDB.AddPreimage(interpreter.hasherBuf, data) } @@ -390,16 +390,21 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) // opExtCodeHash returns the code hash of a specified account. // There are several cases when the function is called, while we can relay everything // to `state.GetCodeHash` function to ensure the correctness. -// (1) Caller tries to get the code hash of a normal contract account, state +// +// (1) Caller tries to get the code hash of a normal contract account, state +// // should return the relative code hash and set it as the result. // -// (2) Caller tries to get the code hash of a non-existent account, state should +// (2) Caller tries to get the code hash of a non-existent account, state should +// // return common.Hash{} and zero will be set as the result. // -// (3) Caller tries to get the code hash for an account without contract code, +// (3) Caller tries to get the code hash for an account without contract code, +// // state should return emptyCodeHash(0xc5d246...) as the result. // -// (4) Caller tries to get the code hash of a precompiled account, the result +// (4) Caller tries to get the code hash of a precompiled account, the result +// // should be zero or emptyCodeHash. // // It is worth noting that in order to avoid unnecessary create and clean, @@ -408,10 +413,12 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) // If the precompile account is not transferred any amount on a private or // customized chain, the return value will be zero. // -// (5) Caller tries to get the code hash for an account which is marked as suicided +// (5) Caller tries to get the code hash for an account which is marked as suicided +// // in the current transaction, the code hash of this account should be returned. // -// (6) Caller tries to get the code hash for an account which is marked as deleted, +// (6) Caller tries to get the code hash for an account which is marked as deleted, +// // this account should be regarded as a non-existent account and zero should be returned. func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() diff --git a/core/vm/logger.go b/core/vm/logger.go index f8f08e726..131f83213 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -105,6 +105,10 @@ func (s *StructLog) ErrorString() string { // Note that reference types are actual VM data structures; make copies // if you need to retain them beyond the current call. type EVMLogger interface { + // Transaction level + CaptureTxStart(gasLimit uint64) + CaptureTxEnd(restGas uint64) + CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) @@ -147,6 +151,10 @@ func (l *StructLogger) Reset() { l.err = nil } +func (*StructLogger) CaptureTxStart(gasLimit uint64) {} + +func (*StructLogger) CaptureTxEnd(restGas uint64) {} + // CaptureStart implements the EVMLogger interface to initialize the tracing operation. func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { l.env = env @@ -307,6 +315,15 @@ func NewMarkdownLogger(cfg *LogConfig, writer io.Writer) *mdLogger { return l } +// CaptureTxStart implements the Tracer interface and is invoked at the beginning of +// transaction processing. +func (t *mdLogger) CaptureTxStart(gasLimit uint64) { +} + +// CaptureTxStart implements the Tracer interface and is invoked at the end of +// transaction processing. +func (t *mdLogger) CaptureTxEnd(restGas uint64) {} + func (t *mdLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { t.env = env if !create { diff --git a/core/vm/logger_json.go b/core/vm/logger_json.go index c249dba7e..8c4fbf3dc 100644 --- a/core/vm/logger_json.go +++ b/core/vm/logger_json.go @@ -42,6 +42,15 @@ func NewJSONLogger(cfg *LogConfig, writer io.Writer) *JSONLogger { return l } +// CaptureTxStart implements the Tracer interface and is invoked at the beginning of +// transaction processing. +func (t *JSONLogger) CaptureTxStart(gasLimit uint64) { +} + +// CaptureTxStart implements the Tracer interface and is invoked at the end of +// transaction processing. +func (t *JSONLogger) CaptureTxEnd(restGas uint64) {} + func (l *JSONLogger) CaptureStart(env *EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { l.env = env } diff --git a/eth/abi.go b/eth/abi.go index c76b58bc3..1033c3f66 100644 --- a/eth/abi.go +++ b/eth/abi.go @@ -21,6 +21,25 @@ const chainConfigABI = ` "name": "ActiveValidatorsLengthChanged", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "share", + "type": "uint16" + } + ], + "name": "DistributeRewardsShareChanged", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -78,6 +97,25 @@ const chainConfigABI = ` "name": "FelonyThresholdChanged", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "preValue", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newValue", + "type": "address" + } + ], + "name": "FoundationAddressChanged", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -142,6 +180,25 @@ const chainConfigABI = ` "name": "FreeGasAddressSizeChanged", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "preValue", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newValue", + "type": "uint256" + } + ], + "name": "GasPriceChanged", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -250,6 +307,19 @@ const chainConfigABI = ` "name": "ValidatorJailEpochLengthChanged", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "share", + "type": "uint16" + } + ], + "name": "ValidatorRewardsShareChanged", + "type": "event" + }, { "inputs": [], "name": "freeGasAddressAdmin", @@ -711,6 +781,111 @@ const chainConfigABI = ` "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newValue", + "type": "uint256" + } + ], + "name": "setGasPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getGasPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDistributeRewardsShares", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + }, + { + "components": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint16", + "name": "share", + "type": "uint16" + } + ], + "internalType": "struct IChainConfig.DistributeRewardsShare[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "validatorShare", + "type": "uint16" + }, + { + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + }, + { + "internalType": "uint16[]", + "name": "shares", + "type": "uint16[]" + } + ], + "name": "updateDistributeRewardsShares", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newValue", + "type": "address" + } + ], + "name": "setFoundationAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getFoundationAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" } ] ` diff --git a/eth/api_backend.go b/eth/api_backend.go index daf6c19ec..2cf670831 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -19,6 +19,7 @@ package eth import ( "context" "errors" + "github.com/ethereum/go-ethereum/log" "math/big" "github.com/ethereum/go-ethereum/accounts" @@ -276,6 +277,21 @@ func (b *EthAPIBackend) Downloader() *downloader.Downloader { } func (b *EthAPIBackend) SuggestPrice(ctx context.Context) (*big.Int, error) { + //Fncy2 Update + if b.ChainConfig().IsFncy2(b.Chain().CurrentBlock().Header().Number) { + suggestPrice, err := b.gpo.SuggestPrice(ctx) + gasPrice := b.eth.TxPool().GasPriceWithoutLock() + log.Debug("suggestPrice", "gpo.SuggestPrice", suggestPrice, "gasPrice", gasPrice) + if err == nil { + if suggestPrice.Cmp(gasPrice) < 0 { + return gasPrice, nil + } + return suggestPrice, nil + } else { + log.Warn("gpo.SuggestPrice ", "error ", err) + return gasPrice, nil + } + } return b.gpo.SuggestPrice(ctx) } diff --git a/eth/backend.go b/eth/backend.go index 7aafbe28e..acafba7d9 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -64,6 +64,8 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) +var maxPrice = big.NewInt(1200000 * params.GWei) + // Config contains the configuration options of the ETH protocol. // Deprecated: use ethconfig.Config instead. type Config = ethconfig.Config @@ -225,7 +227,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.TxPool.Journal != "" { config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) } - eth.txPool = core.NewEnhanceTxPool(config.TxPool, chainConfig, eth.blockchain, getCurrentGasFreeAddressMapFunc(ethAPI)) + //getCurrentGasPriceFunc + eth.txPool = core.NewEnhanceTxPool(config.TxPool, chainConfig, eth.blockchain, getCurrentGasFreeAddressMapFunc(ethAPI), getCurrentGasPriceFunc(eth, ethAPI)) // Permit the downloader to use the trie cache allowance during fast sync cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit @@ -599,6 +602,59 @@ func (s *Ethereum) Stop() error { return nil } +func getCurrentGasPriceFunc(eth *Ethereum, ee *ethapi.PublicBlockChainAPI) func(common.Hash) (*big.Int, error) { + return func(blockHash common.Hash) (*big.Int, error) { + // block + blockNr := rpc.BlockNumberOrHashWithHash(blockHash, false) + // method + method := "getGasPrice" + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // cancel when we are finished consuming integers + chainConfig, err := abi.JSON(strings.NewReader(chainConfigABI)) + if err != nil { + log.Error("Unable to abi.JSON for getGasPrice", "error", err) + return nil, err + } + data, err := chainConfig.Pack(method) + if err != nil { + log.Error("Unable to pack tx for getGasPrice", "error", err) + return nil, err + } + // call + msgData := (hexutil.Bytes)(data) + toAddress := common.HexToAddress(systemcontract.ChainConfigContract) + gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) + result, err := ee.Call(ctx, ethapi.CallArgs{ + Gas: &gas, + To: &toAddress, + Data: &msgData, + }, blockNr, nil) + if err != nil { + return nil, err + } + gasPrice := big.NewInt(0) + if err := chainConfig.UnpackIntoInterface(&gasPrice, method, result); err != nil { + return nil, err + } + if gasPrice != nil && gasPrice.Cmp(common.Big0) > 0 { + if eth.APIBackend.gpo != nil { + if eth.APIBackend.gpo.GetDefaultPrice() == nil || eth.APIBackend.gpo.GetDefaultPrice().Cmp(gasPrice) != 0 { + eth.APIBackend.gpo.SetDefaultPrice(gasPrice) + } + if eth.APIBackend.gpo.GetMaxPrice() == nil || eth.APIBackend.gpo.GetMaxPrice().Cmp(maxPrice) != 0 { + eth.APIBackend.gpo.SetMaxPrice(maxPrice) + } + } + if eth.gasPrice == nil || eth.gasPrice.Cmp(gasPrice) != 0 { + eth.lock.Lock() + eth.gasPrice = gasPrice + eth.lock.Unlock() + } + } + return gasPrice, nil + } +} // getCurrentGasFreeAddressMapFunc get current GasFreeAddressMapFunc func getCurrentGasFreeAddressMapFunc(ee *ethapi.PublicBlockChainAPI) func(common.Hash) (map[common.Address]uint, error) { diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index bc8fa81a4..881ed422f 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -98,6 +98,20 @@ func NewOracle(backend OracleBackend, params Config) *Oracle { } } +func (gpo *Oracle) SetDefaultPrice(defaultPrice *big.Int) { + gpo.defaultPrice = defaultPrice +} +func (gpo *Oracle) GetDefaultPrice() *big.Int { + return gpo.defaultPrice +} + +func (gpo *Oracle) SetMaxPrice(maxPrice *big.Int) { + gpo.maxPrice = maxPrice +} +func (gpo *Oracle) GetMaxPrice() *big.Int { + return gpo.maxPrice +} + // SuggestPrice returns a gasprice so that newly created transaction can // have a very high chance to be included in the following blocks. func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) { diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 8df152fd0..0e1f1b3f2 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -20,6 +20,7 @@ import ( "bufio" "bytes" "context" + "encoding/json" "errors" "fmt" "io/ioutil" @@ -172,6 +173,8 @@ type TraceConfig struct { Tracer *string Timeout *string Reexec *uint64 + + TracerConfig json.RawMessage } // TraceCallConfig is the config for traceCall API. It holds one more @@ -935,7 +938,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex return nil, err } } - if t, err := New(*config.Tracer, txctx); err != nil { + if t, err := New(*config.Tracer, txctx, config.TracerConfig); err != nil { return nil, err } else { deadlineCtx, cancel := context.WithTimeout(ctx, timeout) diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go index b8e035e6f..399aeb8dd 100644 --- a/eth/tracers/js/tracer.go +++ b/eth/tracers/js/tracer.go @@ -424,7 +424,7 @@ type jsTracer struct { // New instantiates a new tracer instance. code specifies a Javascript snippet, // which must evaluate to an expression returning an object with 'step', 'fault' // and 'result' functions. -func newJsTracer(code string, ctx *tracers2.Context) (tracers2.Tracer, error) { +func newJsTracer(code string, ctx *tracers2.Context, cfg json.RawMessage) (tracers2.Tracer, error) { if c, ok := assetTracers[code]; ok { code = c } @@ -679,6 +679,15 @@ func wrapError(context string, err error) error { return fmt.Errorf("%v in server-side tracer function '%v'", err, context) } +// CaptureTxStart implements the Tracer interface and is invoked at the beginning of +// transaction processing. +func (jst *jsTracer) CaptureTxStart(gasLimit uint64) { +} + +// CaptureTxStart implements the Tracer interface and is invoked at the end of +// transaction processing. +func (t *jsTracer) CaptureTxEnd(restGas uint64) {} + // CaptureStart implements the Tracer interface to initialize the tracing operation. func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { jst.env = env diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 16ea75aa4..0804db9a0 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -56,13 +56,22 @@ type callTracer struct { // newCallTracer returns a native go tracer which tracks // call frames of a tx, and implements vm.EVMLogger. -func newCallTracer() tracers.Tracer { +func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { // First callframe contains tx context info // and is populated on start and end. t := &callTracer{callstack: make([]callFrame, 1)} - return t + return t, nil } +// CaptureTxStart implements the Tracer interface and is invoked at the beginning of +// transaction processing. +func (t *callTracer) CaptureTxStart(gasLimit uint64) { +} + +// CaptureTxStart implements the Tracer interface and is invoked at the end of +// transaction processing. +func (t *callTracer) CaptureTxEnd(restGas uint64) {} + // CaptureStart implements the EVMLogger interface to initialize the tracing operation. func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { t.env = env diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index ee110ef7d..65ccd7017 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -35,8 +35,14 @@ func init() { type noopTracer struct{} // newNoopTracer returns a new noop tracer. -func newNoopTracer() tracers.Tracer { - return &noopTracer{} +func newNoopTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { + return &noopTracer{}, nil +} + +func (l *noopTracer) CaptureTxStart(gasLimit uint64) { +} + +func (l *noopTracer) CaptureTxEnd(restGas uint64) { } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go new file mode 100644 index 000000000..fe4866e26 --- /dev/null +++ b/eth/tracers/native/prestate.go @@ -0,0 +1,276 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package native + +import ( + "encoding/json" + "github.com/ethereum/go-ethereum/common/hexutil" + "math/big" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers" +) + +func init() { + register("stateDiff", newStateDiffTracer) +} + +type state = map[common.Address]account +type account struct { + Balance string `json:"balance,omitempty"` + Nonce uint64 `json:"nonce,omitempty"` + storage map[common.Hash]common.Hash +} + +func (a account) exists() bool { + bi := new(big.Int) + bi.SetString(a.Balance[2:], 16) + return a.Nonce > 0 || (bi.Sign() != 0) +} + +type stateDiffTracer struct { + env *vm.EVM + pre state + post state + create bool + to common.Address + gasLimit uint64 // Amount of gas bought for the whole tx + interrupt uint32 // Atomic flag to signal execution interruption + reason error // Textual reason for the interruption + + config stateDiffTracerConfig + created map[common.Address]bool + deleted map[common.Address]bool +} + +type stateDiffTracerConfig struct { + DiffMode bool `json:"diffMode"` // If true, this tracer will return state modifications +} + +func newStateDiffTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { + var config stateDiffTracerConfig + if cfg != nil { + if err := json.Unmarshal(cfg, &config); err != nil { + return nil, err + } + } + // and is populated on start and end. + return &stateDiffTracer{ + pre: state{}, + post: state{}, + config: config, + created: make(map[common.Address]bool), + deleted: make(map[common.Address]bool), + }, nil +} + +// CaptureStart implements the EVMLogger interface to initialize the tracing operation. +func (t *stateDiffTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { + t.env = env + t.create = create + t.to = to + + t.lookupAccount(from) + t.lookupAccount(to) + t.lookupAccount(env.Context.Coinbase) + //t.lookupAccount(consensus.SystemAddress) + + // The recipient balance includes the value transferred. + toAccount := t.pre[to] + toBal := hexutil.MustDecodeBig(toAccount.Balance) + toBal = new(big.Int).Sub(toBal, value) + toAccount.Balance = hexutil.EncodeBig(toBal) + t.pre[to] = toAccount + + // The sender balance is after reducing: value and gasLimit. + // We need to re-add them to get the pre-tx balance. + fromAccount := t.pre[from] + fromBal := hexutil.MustDecodeBig(fromAccount.Balance) + gasPrice := env.TxContext.GasPrice + consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit)) + fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas)) + fromAccount.Balance = hexutil.EncodeBig(fromBal) + fromAccount.Nonce-- + t.pre[from] = fromAccount + + if create && t.config.DiffMode { + t.created[to] = true + } +} + +// CaptureEnd is called after the call finishes to finalize the tracing. +func (t *stateDiffTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { + if t.config.DiffMode { + return + } + + if t.create { + // Keep existing account prior to contract creation at that address + if s := t.pre[t.to]; !s.exists() { + // Exclude newly created contract. + delete(t.pre, t.to) + } + } +} + +// CaptureState implements the EVMLogger interface to trace a single step of VM execution. +func (t *stateDiffTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { + stack := scope.Stack + stackData := stack.Data() + stackLen := len(stackData) + caller := scope.Contract.Address() + switch { + case stackLen >= 1 && (op == vm.SLOAD || op == vm.SSTORE): + slot := common.Hash(stackData[stackLen-1].Bytes32()) + t.lookupStorage(caller, slot) + case stackLen >= 1 && (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT): + addr := common.Address(stackData[stackLen-1].Bytes20()) + t.lookupAccount(addr) + if op == vm.SELFDESTRUCT { + t.deleted[caller] = true + } + case stackLen >= 5 && (op == vm.DELEGATECALL || op == vm.CALL || op == vm.STATICCALL || op == vm.CALLCODE): + addr := common.Address(stackData[stackLen-2].Bytes20()) + t.lookupAccount(addr) + case op == vm.CREATE: + nonce := t.env.StateDB.GetNonce(caller) + addr := crypto.CreateAddress(caller, nonce) + t.lookupAccount(addr) + t.created[addr] = true + case stackLen >= 4 && op == vm.CREATE2: + offset := stackData[stackLen-2] + size := stackData[stackLen-3] + init := scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) + inithash := crypto.Keccak256(init) + salt := stackData[stackLen-4] + addr := crypto.CreateAddress2(caller, salt.Bytes32(), inithash) + t.lookupAccount(addr) + t.created[addr] = true + } +} + +// CaptureFault implements the EVMLogger interface to trace an execution fault. +func (t *stateDiffTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { +} + +// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *stateDiffTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { +} + +// CaptureExit is called when EVM exits a scope, even if the scope didn't +// execute any code. +func (t *stateDiffTracer) CaptureExit(output []byte, gasUsed uint64, err error) { +} + +func (t *stateDiffTracer) CaptureTxStart(gasLimit uint64) { + t.gasLimit = gasLimit +} + +func (t *stateDiffTracer) CaptureTxEnd(restGas uint64) { + if !t.config.DiffMode { + return + } + + //for addr, state := range t.pre { + for addr, _ := range t.pre { + // The deleted account's state is pruned from `post` but kept in `pre` + if _, ok := t.deleted[addr]; ok { + continue + } + modified := false + postAccount := account{storage: make(map[common.Hash]common.Hash)} + newBalance := bigToHex(t.env.StateDB.GetBalance(addr)) + newNonce := t.env.StateDB.GetNonce(addr) + //newCode := t.env.StateDB.GetCode(addr) + + if newBalance != t.pre[addr].Balance { + modified = true + postAccount.Balance = newBalance + } + if newNonce != t.pre[addr].Nonce { + modified = true + postAccount.Nonce = newNonce + } + + if modified { + t.post[addr] = postAccount + } else { + // if state is not modified, then no need to include into the pre state + delete(t.pre, addr) + } + } + // the new created contracts' prestate were empty, so delete them + for a := range t.created { + // the created contract maybe exists in statedb before the creating tx + if s := t.pre[a]; !s.exists() { + delete(t.pre, a) + } + } +} + +// GetResult returns the json-encoded nested list of call traces, and any +// error arising from the encoding or forceful termination (via `Stop`). +func (t *stateDiffTracer) GetResult() (json.RawMessage, error) { + var res []byte + var err error + if t.config.DiffMode { + res, err = json.Marshal(struct { + Post state `json:"post"` + Pre state `json:"pre"` + }{t.post, t.pre}) + } else { + res, err = json.Marshal(t.pre) + } + if err != nil { + return nil, err + } + return json.RawMessage(res), t.reason +} + +// Stop terminates execution of the tracer at the first opportune moment. +func (t *stateDiffTracer) Stop(err error) { + t.reason = err + atomic.StoreUint32(&t.interrupt, 1) +} + +// lookupAccount fetches details of an account and adds it to the prestate +// if it doesn't exist there. +func (t *stateDiffTracer) lookupAccount(addr common.Address) { + if _, ok := t.pre[addr]; ok { + return + } + + t.pre[addr] = account{ + Balance: bigToHex(t.env.StateDB.GetBalance(addr)), + Nonce: t.env.StateDB.GetNonce(addr), + storage: make(map[common.Hash]common.Hash), + } +} + +// lookupStorage fetches the requested storage slot and adds +// it to the prestate of the given contract. It assumes `lookupAccount` +// has been performed on the contract before. +func (t *stateDiffTracer) lookupStorage(addr common.Address, key common.Hash) { + if _, ok := t.pre[addr].storage[key]; ok { + return + } + t.pre[addr].storage[key] = t.env.StateDB.GetState(addr, key) +} diff --git a/eth/tracers/native/tracer.go b/eth/tracers/native/tracer.go index 3158654f3..187d89fa1 100644 --- a/eth/tracers/native/tracer.go +++ b/eth/tracers/native/tracer.go @@ -27,14 +27,17 @@ Aside from implementing the tracer, it also needs to register itself, using the Example: ```golang -func init() { - register("noopTracerNative", newNoopTracer) -} + + func init() { + register("noopTracerNative", newNoopTracer) + } + ``` */ package native import ( + "encoding/json" "errors" "github.com/ethereum/go-ethereum/eth/tracers" @@ -45,6 +48,9 @@ func init() { tracers.RegisterLookup(false, lookup) } +// ctorFn is the constructor signature of a native tracer. +type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error) + /* ctors is a map of package-local tracer constructors. @@ -57,23 +63,23 @@ The go spec (https://golang.org/ref/spec#Package_initialization) says Hence, we cannot make the map in init, but must make it upon first use. */ -var ctors map[string]func() tracers.Tracer +var ctors map[string]ctorFn // register is used by native tracers to register their presence. -func register(name string, ctor func() tracers.Tracer) { +func register(name string, ctor ctorFn) { if ctors == nil { - ctors = make(map[string]func() tracers.Tracer) + ctors = make(map[string]ctorFn) } ctors[name] = ctor } // lookup returns a tracer, if one can be matched to the given name. -func lookup(name string, ctx *tracers.Context) (tracers.Tracer, error) { +func lookup(name string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { if ctors == nil { - ctors = make(map[string]func() tracers.Tracer) + ctors = make(map[string]ctorFn) } if ctor, ok := ctors[name]; ok { - return ctor(), nil + return ctor(ctx, cfg) } return nil, errors.New("no tracer found") } diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index e8fdc08f1..710d3acd9 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -43,7 +43,7 @@ type Tracer interface { Stop(err error) } -type lookupFunc func(string, *Context) (Tracer, error) +type lookupFunc func(string, *Context, json.RawMessage) (Tracer, error) var ( lookups []lookupFunc @@ -63,9 +63,9 @@ func RegisterLookup(wildcard bool, lookup lookupFunc) { // New returns a new instance of a tracer, by iterating through the // registered lookups. -func New(code string, ctx *Context) (Tracer, error) { +func New(code string, ctx *Context, cfg json.RawMessage) (Tracer, error) { for _, lookup := range lookups { - if tracer, err := lookup(code, ctx); err == nil { + if tracer, err := lookup(code, ctx, cfg); err == nil { return tracer, nil } } diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 578b10f09..421c7dafe 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -94,6 +94,16 @@ func (ec *Client) BlockNumber(ctx context.Context) (uint64, error) { return uint64(result), err } +// BlockReceipts returns the receipts of a given block number or hash. +func (ec *Client) BlockReceipts(ctx context.Context, hash common.Hash) ([]*types.Receipt, error) { + var r []*types.Receipt + err := ec.c.CallContext(ctx, &r, "eth_getBlockReceipts", hash.String()) + if err == nil && r == nil { + return nil, ethereum.NotFound + } + return r, err +} + type rpcBlock struct { Hash common.Hash `json:"hash"` Transactions []rpcTransaction `json:"transactions"` diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1a02ec5ef..1828aa1f4 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -656,10 +656,10 @@ func (s *PublicBlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.H } // GetBlockByNumber returns the requested canonical block. -// * When blockNr is -1 the chain head is returned. -// * When blockNr is -2 the pending chain head is returned. -// * When fullTx is true all transactions in the block are returned, otherwise -// only the transaction hash is returned. +// - When blockNr is -1 the chain head is returned. +// - When blockNr is -2 the pending chain head is returned. +// - When fullTx is true all transactions in the block are returned, otherwise +// only the transaction hash is returned. func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { block, err := s.b.BlockByNumber(ctx, number) if block != nil && err == nil { @@ -816,6 +816,68 @@ func (args *CallArgs) ToMessage(globalGasCap uint64) types.Message { return msg } +// GetBlockReceipts returns the block receipts for the given block hash or number or tag. +func (api *PublicBlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) { + block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash) + if block == nil || err != nil { + // When the block doesn't exist, the RPC method should return JSON null + // as per specification. + return nil, nil + } + receipts, err := api.b.GetReceipts(ctx, block.Hash()) + if err != nil { + return nil, err + } + txs := block.Transactions() + if len(txs) != len(receipts) { + return nil, fmt.Errorf("receipts length mismatch: %d vs %d", len(txs), len(receipts)) + } + + blockHash := block.Hash() + blockNumber := block.NumberU64() + txReceipts := make([]map[string]interface{}, 0, len(txs)) + for i, receipt := range receipts { + tx := txs[i] + var signer types.Signer = types.FrontierSigner{} + if tx.Protected() { + signer = types.NewEIP155Signer(tx.ChainId()) + } + from, _ := types.Sender(signer, tx) + + fields := map[string]interface{}{ + "blockHash": blockHash, + "blockNumber": hexutil.Uint64(blockNumber), + "transactionHash": tx.Hash(), + "transactionIndex": hexutil.Uint64(i), + "from": from, + "to": tx.To(), + "gasUsed": hexutil.Uint64(receipt.GasUsed), + "cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed), + "contractAddress": nil, + "logs": receipt.Logs, + "logsBloom": receipt.Bloom, + } + + // Assign receipt status or post state. + if len(receipt.PostState) > 0 { + fields["root"] = hexutil.Bytes(receipt.PostState) + } else { + fields["status"] = hexutil.Uint(receipt.Status) + } + if receipt.Logs == nil { + fields["logs"] = [][]*types.Log{} + } + // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation + if receipt.ContractAddress != (common.Address{}) { + fields["contractAddress"] = receipt.ContractAddress + } + + txReceipts = append(txReceipts, fields) + } + + return txReceipts, nil +} + // OverrideAccount indicates the overriding fields of account during the execution // of a message call. // Note, state and stateDiff can't be specified at the same time. If state is diff --git a/miner/worker.go b/miner/worker.go index b9a06208b..e711c8084 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -979,6 +979,7 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st } block, receipts, err := w.engine.FinalizeAndAssemble(w.chain, types.CopyHeader(w.current.header), s, w.current.txs, uncles, w.current.receipts) if err != nil { + log.Warn("Miner worker commit failed", "block number", w.current.header.Number, " error", err) return err } if w.isRunning() { diff --git a/params/config.go b/params/config.go index fd4a3e499..936eeb02c 100644 --- a/params/config.go +++ b/params/config.go @@ -51,6 +51,8 @@ var ( big.NewInt(0), big.NewInt(0), big.NewInt(0), + big.NewInt(0), + big.NewInt(0), nil, nil, nil, @@ -80,7 +82,9 @@ var ( big.NewInt(0), big.NewInt(0), big.NewInt(0), - nil, + big.NewInt(0), + big.NewInt(0), + big.NewInt(0), &CliqueConfig{Period: 0, Epoch: 30000}, nil, } @@ -104,6 +108,8 @@ var ( big.NewInt(0), big.NewInt(0), big.NewInt(0), + big.NewInt(0), + big.NewInt(0), nil, nil, nil, } @@ -171,9 +177,8 @@ type ChainConfig struct { EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) EIP150Hash common.Hash `json:"eip150Hash,omitempty"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) - EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block - EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block - + EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block + EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated) PetersburgBlock *big.Int `json:"petersburgBlock,omitempty"` // Petersburg switch block (nil = same as Constantinople) @@ -188,13 +193,13 @@ type ChainConfig struct { EWASMBlock *big.Int `json:"ewasmBlock,omitempty"` // EWASM switch block (nil = no fork, 0 = already activated) RamanujanBlock *big.Int `json:"ramanujanBlock,omitempty" toml:",omitempty"` // ramanujanBlock switch block (nil = no fork, 0 = already activated) CatalystBlock *big.Int `json:"catalystBlock,omitempty"` // Catalyst switch block (nil = no fork, 0 = already on catalyst) - RamanujanBlock *big.Int `json:"ramanujanBlock,omitempty" toml:",omitempty"` // ramanujanBlock switch block (nil = no fork, 0 = already activated) - NielsBlock *big.Int `json:"nielsBlock,omitempty" toml:",omitempty"` // nielsBlock switch block (nil = no fork, 0 = already activated) - MirrorSyncBlock *big.Int `json:"mirrorSyncBlock,omitempty" toml:",omitempty"` // mirrorSyncBlock switch block (nil = no fork, 0 = already activated) - BrunoBlock *big.Int `json:"brunoBlock,omitempty" toml:",omitempty"` // brunoBlock switch block (nil = no fork, 0 = already activated) - + RamanujanBlock *big.Int `json:"ramanujanBlock,omitempty" toml:",omitempty"` // ramanujanBlock switch block (nil = no fork, 0 = already activated) + NielsBlock *big.Int `json:"nielsBlock,omitempty" toml:",omitempty"` // nielsBlock switch block (nil = no fork, 0 = already activated) + MirrorSyncBlock *big.Int `json:"mirrorSyncBlock,omitempty" toml:",omitempty"` // mirrorSyncBlock switch block (nil = no fork, 0 = already activated) + BrunoBlock *big.Int `json:"brunoBlock,omitempty" toml:",omitempty"` // brunoBlock switch block (nil = no fork, 0 = already activated) BlockRewardsBlock *big.Int `json:"blockRewardsBlock,omitempty" toml:",omitempty"` - + Contract48kBlock *big.Int `json:"contract48kBlock,omitempty" toml:",omitempty"` // contract48kBlock switch block (nil = no fork, 0 = already activated) + Fncy2Block *big.Int `json:"fncy2Block,omitempty" toml:",omitempty"` // fncy2Block switch block (nil = no fork, 0 = already activated) // Various consensus engines Clique *CliqueConfig `json:"clique,omitempty" toml:",omitempty"` Parlia *ParliaConfig `json:"parlia,omitempty" toml:",omitempty"` @@ -213,9 +218,10 @@ func (c *CliqueConfig) String() string { // ParliaConfig is the consensus engine configs for proof-of-staked-authority based sealing. type ParliaConfig struct { - Period uint64 `json:"period"` // Number of seconds between blocks to enforce - Epoch uint64 `json:"epoch"` // Epoch length to update validatorSet - BlockRewards *big.Int `json:"blockRewards"` // Block rewards to be paid for each produced block + Period uint64 `json:"period"` // Number of seconds between blocks to enforce + Epoch uint64 `json:"epoch"` // Epoch length to update validatorSet + BlockRewards *big.Int `json:"blockRewards"` // Block rewards to be paid for each produced block + StopMintBlock *big.Int `json:"stopMintBlock"` // Do not continue minting after configuring the block } // String implements the stringer interface, returning the consensus engine details. @@ -275,6 +281,13 @@ func (c *ChainConfig) IsEIP158(num *big.Int) bool { return isForked(c.EIP158Block, num) } +func (c *ChainConfig) IsContract48kBlock(num *big.Int) bool { + return isForked(c.Contract48kBlock, num) +} +func (c *ChainConfig) IsFncy2(num *big.Int) bool { + return isForked(c.Fncy2Block, num) +} + // IsByzantium returns whether num is either equal to the Byzantium fork block or greater. func (c *ChainConfig) IsByzantium(num *big.Int) bool { return isForked(c.ByzantiumBlock, num) @@ -539,12 +552,12 @@ func (err *ConfigCompatError) Error() string { // Rules is a one time interface meaning that it shouldn't be used in between transition // phases. type Rules struct { - ChainID *big.Int - IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool - IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool - IsBerlin, IsCatalyst bool - HasRuntimeUpgrade, HasDeployerProxy bool - HasBlockRewards bool + ChainID *big.Int + IsHomestead, IsEIP150, IsEIP155, IsEIP158, IsContract48kBlock bool + IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool + IsBerlin, IsCatalyst bool + HasRuntimeUpgrade, HasDeployerProxy bool + HasBlockRewards bool } // Rules ensures c's ChainID is not nil. @@ -554,19 +567,20 @@ func (c *ChainConfig) Rules(num *big.Int) Rules { chainID = new(big.Int) } return Rules{ - ChainID: new(big.Int).Set(chainID), - IsHomestead: c.IsHomestead(num), - IsEIP150: c.IsEIP150(num), - IsEIP155: c.IsEIP155(num), - IsEIP158: c.IsEIP158(num), - IsByzantium: c.IsByzantium(num), - IsConstantinople: c.IsConstantinople(num), - IsPetersburg: c.IsPetersburg(num), - IsIstanbul: c.IsIstanbul(num), - IsBerlin: c.IsBerlin(num), - IsCatalyst: c.IsCatalyst(num), - HasRuntimeUpgrade: c.HasRuntimeUpgrade(num), - HasDeployerProxy: c.HasDeployerProxy(num), - HasBlockRewards: c.IsBlockRewardsBlock(num), + ChainID: new(big.Int).Set(chainID), + IsHomestead: c.IsHomestead(num), + IsEIP150: c.IsEIP150(num), + IsEIP155: c.IsEIP155(num), + IsEIP158: c.IsEIP158(num), + IsContract48kBlock: c.IsContract48kBlock(num), + IsByzantium: c.IsByzantium(num), + IsConstantinople: c.IsConstantinople(num), + IsPetersburg: c.IsPetersburg(num), + IsIstanbul: c.IsIstanbul(num), + IsBerlin: c.IsBerlin(num), + IsCatalyst: c.IsCatalyst(num), + HasRuntimeUpgrade: c.HasRuntimeUpgrade(num), + HasDeployerProxy: c.HasDeployerProxy(num), + HasBlockRewards: c.IsBlockRewardsBlock(num), } }