Search in sources :

Example 31 with Block

use of org.aion.zero.impl.types.Block in project aion by aionnetwork.

the class AionBlockchainImpl method isValid.

public boolean isValid(BlockHeader header) {
    /*
         * The block header should already be validated at this point by P2P or mining,
         * but we are including the validation in case future import paths forget to add it.
         */
    if (!this.headerValidator.validate(header, LOG)) {
        return false;
    }
    Block[] threeGenParents = repository.getBlockStore().getThreeGenerationBlocksByHashWithInfo(header.getParentHash());
    Block parentBlock = threeGenParents[0];
    if (parentBlock == null) {
        return false;
    }
    Block grandparentBlock = threeGenParents[1];
    Block greatGrandparentBlock = threeGenParents[2];
    if (header.getSealType() == Seal.PROOF_OF_WORK) {
        if (forkUtility.isUnityForkActive(header.getNumber())) {
            if (grandparentBlock == null || greatGrandparentBlock == null) {
                return false;
            }
            return unityParentBlockHeaderValidator.validate(header, parentBlock.getHeader(), LOG, null) && unityGreatGrandParentBlockHeaderValidator.validate(grandparentBlock.getHeader(), greatGrandparentBlock.getHeader(), header, LOG);
        } else {
            return preUnityParentBlockHeaderValidator.validate(header, parentBlock.getHeader(), LOG, null) && preUnityGrandParentBlockHeaderValidator.validate(parentBlock.getHeader(), grandparentBlock == null ? null : grandparentBlock.getHeader(), header, LOG);
        }
    } else if (header.getSealType() == Seal.PROOF_OF_STAKE) {
        if (!forkUtility.isUnityForkActive(header.getNumber())) {
            LOG.warn("Trying to import a Staking block when the Unity fork is not active.");
            return false;
        }
        if (grandparentBlock == null) {
            LOG.warn("Staking block {} cannot find its grandparent", header.getNumber());
            return false;
        }
        if (forkUtility.isUnityForkBlock(parentBlock.getNumber())) {
            BigInteger expectedDiff = calculateFirstPoSDifficultyAtBlock(parentBlock);
            if (!expectedDiff.equals(header.getDifficultyBI())) {
                return false;
            }
            grandparentBlock = new GenesisStakingBlock(expectedDiff);
        } else if (forkUtility.isNonceForkBlock(parentBlock.getNumber())) {
            BigInteger expectedDiff = calculateFirstPoSDifficultyAtBlock(parentBlock);
            if (!expectedDiff.equals(header.getDifficultyBI())) {
                return false;
            }
        }
        BigInteger stake = null;
        try {
            stake = getStakingContractHelper().getEffectiveStake(new AionAddress(AddressSpecs.computeA0Address(((StakingBlockHeader) header).getSigningPublicKey())), ((StakingBlockHeader) header).getCoinbase(), parentBlock);
        } catch (Exception e) {
            LOG.error("Shutdown due to a fatal error encountered while getting the effective stake.", e);
            System.exit(SystemExitCodes.FATAL_VM_ERROR);
        }
        boolean result = unityParentBlockHeaderValidator.validate(header, parentBlock.getHeader(), LOG, stake);
        if (result) {
            if (forkUtility.isSignatureSwapForkActive(header.getNumber())) {
                result = vrfProofValidator.validate(parentBlock.getHeader(), grandparentBlock.getHeader(), header, LOG) && difficultyValidateAfterSeedNonceFork(grandparentBlock.getHeader(), greatGrandparentBlock.getHeader(), header);
            } else if (forkUtility.isNonceForkActive(header.getNumber())) {
                result = nonceSeedValidator.validate(grandparentBlock.getHeader(), parentBlock.getHeader(), header, LOG) && difficultyValidateAfterSeedNonceFork(grandparentBlock.getHeader(), greatGrandparentBlock.getHeader(), header);
            } else {
                result = unityGreatGrandParentBlockHeaderValidator.validate(grandparentBlock.getHeader(), greatGrandparentBlock.getHeader(), header, LOG);
            }
        }
        return result;
    } else {
        LOG.debug("Invalid header seal type!");
        return false;
    }
}
Also used : AionAddress(org.aion.types.AionAddress) GenesisStakingBlock(org.aion.zero.impl.types.GenesisStakingBlock) Block(org.aion.zero.impl.types.Block) BlockDetailsValidator.isValidBlock(org.aion.zero.impl.valid.BlockDetailsValidator.isValidBlock) GenesisStakingBlock(org.aion.zero.impl.types.GenesisStakingBlock) RetValidPreBlock(org.aion.zero.impl.types.RetValidPreBlock) MiningBlock(org.aion.zero.impl.types.MiningBlock) EventBlock(org.aion.evtmgr.impl.evt.EventBlock) StakingBlock(org.aion.zero.impl.types.StakingBlock) BigInteger(java.math.BigInteger) VmFatalException(org.aion.zero.impl.vm.common.VmFatalException)

Example 32 with Block

use of org.aion.zero.impl.types.Block in project aion by aionnetwork.

the class AionBlockchainImpl method getListOfHashesStartFromBlock.

@Override
public List<byte[]> getListOfHashesStartFromBlock(long blockNumber, int qty) {
    // avoiding errors due to negative qty
    qty = qty < 1 ? 1 : qty;
    long bestNumber = bestBlock.getNumber();
    if (blockNumber > bestNumber) {
        return emptyList();
    }
    if (blockNumber + qty - 1 > bestNumber) {
        qty = (int) (bestNumber - blockNumber + 1);
    }
    long endNumber = blockNumber + qty - 1;
    Block block = getBlockByNumber(endNumber);
    List<byte[]> hashes = repository.getBlockStore().getListHashesEndWith(block.getHash(), qty);
    // asc order of hashes is required in the response
    Collections.reverse(hashes);
    return hashes;
}
Also used : Block(org.aion.zero.impl.types.Block) BlockDetailsValidator.isValidBlock(org.aion.zero.impl.valid.BlockDetailsValidator.isValidBlock) GenesisStakingBlock(org.aion.zero.impl.types.GenesisStakingBlock) RetValidPreBlock(org.aion.zero.impl.types.RetValidPreBlock) MiningBlock(org.aion.zero.impl.types.MiningBlock) EventBlock(org.aion.evtmgr.impl.evt.EventBlock) StakingBlock(org.aion.zero.impl.types.StakingBlock)

Example 33 with Block

use of org.aion.zero.impl.types.Block in project aion by aionnetwork.

the class AionBlockchainImpl method createNewStakingBlock.

private StakingBlock createNewStakingBlock(Block parent, List<AionTransaction> txs, byte[] newSeed, byte[] signingPublicKey, byte[] coinbase) {
    BlockHeader parentHdr = parent.getHeader();
    byte[] sealedSeed = newSeed;
    if (!forkUtility.isUnityForkActive(parentHdr.getNumber() + 1)) {
        LOG.debug("Unity fork has not been enabled! Can't create the staking blocks");
        return null;
    }
    byte[] parentSeed;
    BigInteger newDiff;
    if (parentHdr.getSealType() == Seal.PROOF_OF_STAKE) {
        LOG.warn("Tried to create 2 PoS blocks in a row");
        return null;
    } else if (parentHdr.getSealType() == Seal.PROOF_OF_WORK) {
        if (forkUtility.isUnityForkBlock(parentHdr.getNumber())) {
            // this is the first PoS block, use all zeroes as seed, and totalStake / 10 as difficulty
            parentSeed = GENESIS_SEED;
            newDiff = calculateFirstPoSDifficultyAtBlock(parent);
        } else if (forkUtility.isNonceForkBlock(parentHdr.getNumber())) {
            BlockHeader parentStakingBlock = getParent(parentHdr).getHeader();
            parentSeed = ((StakingBlockHeader) parentStakingBlock).getSeedOrProof();
            newDiff = calculateFirstPoSDifficultyAtBlock(parent);
            forkUtility.setNonceForkResetDiff(newDiff);
        } else {
            Block[] blockFamily = repository.getBlockStore().getTwoGenerationBlocksByHashWithInfo(parentHdr.getParentHash());
            Objects.requireNonNull(blockFamily[0]);
            BlockHeader parentStakingBlock = blockFamily[0].getHeader();
            BlockHeader parentStakingBlocksParent = blockFamily[1].getHeader();
            parentSeed = ((StakingBlockHeader) parentStakingBlock).getSeedOrProof();
            newDiff = chainConfiguration.getUnityDifficultyCalculator().calculateDifficulty(parentStakingBlock, parentStakingBlocksParent);
        }
    } else {
        throw new IllegalStateException("Invalid block type");
    }
    long newTimestamp;
    AionAddress coinbaseAddress = new AionAddress(coinbase);
    if (signingPublicKey != null) {
        // Create block template for the external stakers.
        byte[] proofHash = null;
        if (forkUtility.isSignatureSwapForkBlock(parent.getNumber() - 1)) {
            if (!VRF_Ed25519.verify(parentSeed, newSeed, signingPublicKey)) {
                LOG.debug("Seed verification failed! previousProof:{} newProof:{} pKey:{}", ByteUtil.toHexString(parentSeed), ByteUtil.toHexString(newSeed), ByteUtil.toHexString(signingPublicKey));
                return null;
            }
            proofHash = VRF_Ed25519.generateProofHash(newSeed);
        } else if (forkUtility.isSignatureSwapForkActive(parent.getNumber() + 1)) {
            byte[] parentSeedHash = VRF_Ed25519.generateProofHash(parentSeed);
            if (!VRF_Ed25519.verify(parentSeedHash, newSeed, signingPublicKey)) {
                LOG.debug("Seed verification failed! previousProof:{} newProof:{} pKey:{}", ByteUtil.toHexString(parentSeed), ByteUtil.toHexString(newSeed), ByteUtil.toHexString(signingPublicKey));
                return null;
            }
            proofHash = VRF_Ed25519.generateProofHash(newSeed);
        } else {
            if (!ECKeyEd25519.verify(parentSeed, newSeed, signingPublicKey)) {
                LOG.debug("Seed verification failed! previousSeed:{} newSeed:{} pKey:{}", ByteUtil.toHexString(parentSeed), ByteUtil.toHexString(newSeed), ByteUtil.toHexString(signingPublicKey));
                return null;
            }
            if (forkUtility.isNonceForkActive(parentHdr.getNumber() + 1)) {
                // new seed generation
                BlockHeader parentStakingBlock = getParent(parentHdr).getHeader();
                // retrieve components
                parentSeed = ((StakingBlockHeader) parentStakingBlock).getSeedOrProof();
                byte[] signerAddress = new AionAddress(AddressSpecs.computeA0Address(signingPublicKey)).toByteArray();
                ;
                byte[] powMineHash = ((MiningBlock) parent).getHeader().getMineHash();
                byte[] powNonce = ((MiningBlock) parent).getNonce();
                int lastIndex = parentSeed.length + signerAddress.length + powMineHash.length + powNonce.length;
                byte[] concatenated = new byte[lastIndex + 1];
                System.arraycopy(parentSeed, 0, concatenated, 0, parentSeed.length);
                System.arraycopy(signerAddress, 0, concatenated, parentSeed.length, signerAddress.length);
                System.arraycopy(powMineHash, 0, concatenated, parentSeed.length + signerAddress.length, powMineHash.length);
                System.arraycopy(powNonce, 0, concatenated, parentSeed.length + signerAddress.length + powMineHash.length, powNonce.length);
                concatenated[lastIndex] = 0;
                byte[] hash1 = h256(concatenated);
                concatenated[lastIndex] = 1;
                byte[] hash2 = h256(concatenated);
                sealedSeed = new byte[hash1.length + hash2.length];
                System.arraycopy(hash1, 0, sealedSeed, 0, hash1.length);
                System.arraycopy(hash2, 0, sealedSeed, hash1.length, hash2.length);
            }
        }
        AionAddress signingAddress = new AionAddress(AddressSpecs.computeA0Address(signingPublicKey));
        BigInteger stakes = null;
        try {
            stakes = getStakingContractHelper().getEffectiveStake(signingAddress, coinbaseAddress, parent);
        } catch (Exception e) {
            LOG.error("Shutdown due to a fatal error encountered while getting the effective stake.", e);
            System.exit(SystemExitCodes.FATAL_VM_ERROR);
        }
        if (stakes.signum() < 1) {
            LOG.debug("The caller {} with coinbase {} has no stake ", signingAddress.toString(), coinbase.toString());
            return null;
        }
        long newDelta = StakingDeltaCalculator.calculateDelta(proofHash == null ? sealedSeed : proofHash, newDiff, stakes);
        newTimestamp = Long.max(parent.getHeader().getTimestamp() + newDelta, parent.getHeader().getTimestamp() + 1);
    } else {
        newTimestamp = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
        if (parentHdr.getTimestamp() >= newTimestamp) {
            newTimestamp = parentHdr.getTimestamp() + 1;
        }
    }
    StakingBlock block;
    try {
        StakingBlockHeader.Builder headerBuilder = StakingBlockHeader.Builder.newInstance().withParentHash(parent.getHash()).withCoinbase(coinbaseAddress).withNumber(parentHdr.getNumber() + 1).withTimestamp(newTimestamp).withExtraData(minerExtraData).withTxTrieRoot(calcTxTrieRoot(txs)).withEnergyLimit(energyLimitStrategy.getEnergyLimit(parentHdr)).withDifficulty(ByteUtil.bigIntegerToBytes(newDiff, DIFFICULTY_BYTES)).withDefaultStateRoot().withDefaultReceiptTrieRoot().withDefaultLogsBloom().withDefaultSignature().withDefaultSigningPublicKey();
        if (signingPublicKey != null) {
            headerBuilder.withSigningPublicKey(signingPublicKey);
        }
        if (forkUtility.isSignatureSwapForkActive(parentHdr.getNumber() + 1)) {
            headerBuilder.withProof(sealedSeed);
        } else {
            headerBuilder.withSeed(sealedSeed);
        }
        block = new StakingBlock(headerBuilder.build(), txs);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    BigInteger transactionFee = blockPreSeal(parentHdr, block);
    if (transactionFee == null) {
        return null;
    }
    if (signingPublicKey != null) {
        stakingBlockTemplate.putIfAbsent(ByteArrayWrapper.wrap(block.getHeader().getMineHash()), block);
    }
    LOG.debug("GetBlockTemp: {}", block.toString());
    return block;
}
Also used : AionAddress(org.aion.types.AionAddress) StakingBlockHeader(org.aion.zero.impl.types.StakingBlockHeader) MiningBlock(org.aion.zero.impl.types.MiningBlock) VmFatalException(org.aion.zero.impl.vm.common.VmFatalException) BigInteger(java.math.BigInteger) Block(org.aion.zero.impl.types.Block) BlockDetailsValidator.isValidBlock(org.aion.zero.impl.valid.BlockDetailsValidator.isValidBlock) GenesisStakingBlock(org.aion.zero.impl.types.GenesisStakingBlock) RetValidPreBlock(org.aion.zero.impl.types.RetValidPreBlock) MiningBlock(org.aion.zero.impl.types.MiningBlock) EventBlock(org.aion.evtmgr.impl.evt.EventBlock) StakingBlock(org.aion.zero.impl.types.StakingBlock) BlockHeader(org.aion.zero.impl.types.BlockHeader) MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) StakingBlockHeader(org.aion.zero.impl.types.StakingBlockHeader) GenesisStakingBlock(org.aion.zero.impl.types.GenesisStakingBlock) StakingBlock(org.aion.zero.impl.types.StakingBlock)

Example 34 with Block

use of org.aion.zero.impl.types.Block in project aion by aionnetwork.

the class AionBlockchainImpl method tryFastImport.

/**
 * Import block without validity checks and creating the state. Cannot be used for storing the
 * pivot which will not have a parent present in the database.
 *
 * @param block the block to be imported
 * @return a result describing the status of the attempted import
 */
public FastImportResult tryFastImport(final Block block) {
    lock.lock();
    try {
        if (block == null) {
            LOG.debug("Fast sync import attempted with null block or header.");
            return FastImportResult.INVALID_BLOCK;
        }
        if (block.getTimestamp() > (TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) + this.chainConfiguration.getConstants().getClockDriftBufferTime())) {
            LOG.debug("Block {} invalid due to timestamp {}.", block.getShortHash(), block.getTimestamp());
            return FastImportResult.INVALID_BLOCK;
        }
        // check that the block is not already known
        Block known = getBlockByHash(block.getHash());
        if (known != null && known.getNumber() == block.getNumber()) {
            return FastImportResult.KNOWN;
        } else {
            // a child must be present to import the parent
            Block child = getBlockByNumber(block.getNumber() + 1);
            if (child == null || !Arrays.equals(child.getParentHash(), block.getHash())) {
                return FastImportResult.NO_CHILD;
            } else {
                // the total difficulty will be updated after the chain is complete
                repository.getBlockStore().saveBlock(block, ZERO, true);
                LOG.debug("Fast sync block saved: number: {}, hash: {}, child: {}", block.getNumber(), block.getShortHash(), child.getShortHash());
                return FastImportResult.IMPORTED;
            }
        }
    } finally {
        lock.unlock();
    }
}
Also used : Block(org.aion.zero.impl.types.Block) BlockDetailsValidator.isValidBlock(org.aion.zero.impl.valid.BlockDetailsValidator.isValidBlock) GenesisStakingBlock(org.aion.zero.impl.types.GenesisStakingBlock) RetValidPreBlock(org.aion.zero.impl.types.RetValidPreBlock) MiningBlock(org.aion.zero.impl.types.MiningBlock) EventBlock(org.aion.evtmgr.impl.evt.EventBlock) StakingBlock(org.aion.zero.impl.types.StakingBlock)

Example 35 with Block

use of org.aion.zero.impl.types.Block in project aion by aionnetwork.

the class AionBlockchainImpl method tryToConnect.

/**
 * Imports a batch of blocks.
 *
 * @param blockRange the block range to be imported
 * @param peerDisplayId the display identifier for the peer who provided the batch
 * @return a {@link Triple} containing:
 * <ol>
 *     <li>the best block height after the imports,</li>
 *     <li>the set of imported hashes,</li>
 *     <li>the import result for the last imported block</li>
 * </ol>
 */
public Triple<Long, Set<ByteArrayWrapper>, ImportResult> tryToConnect(final List<Block> blockRange, String peerDisplayId) {
    lock.lock();
    try {
        ImportResult importResult = null;
        Set<ByteArrayWrapper> imported = new HashSet<>();
        for (Block block : blockRange) {
            Pair<ImportResult, Long> result = tryToConnectWithTimedExecution(new BlockWrapper(block));
            importResult = result.getLeft();
            long importTime = result.getRight();
            // printing additional information when debug is enabled
            SYNC_LOG.debug("<import-status: node = {}, hash = {}, number = {}, txs = {}, block time = {}, result = {}, time elapsed = {} ns, block td = {}, chain td = {}>", peerDisplayId, block.getShortHash(), block.getNumber(), block.getTransactionsList().size(), block.getTimestamp(), importResult, importTime, block.getTotalDifficulty(), getTotalDifficulty());
            if (checkKernelShutdownForCLI()) {
                break;
            } else if (!importResult.isStored()) {
                // stop at invalid blocks
                return Triple.of(bestBlock.getNumber(), imported, importResult);
            } else {
                imported.add(block.getHashWrapper());
            }
        }
        return Triple.of(bestBlock.getNumber(), imported, importResult);
    } finally {
        lock.unlock();
        checkKernelExit();
    }
}
Also used : ImportResult(org.aion.zero.impl.core.ImportResult) FastImportResult(org.aion.zero.impl.core.FastImportResult) ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper) AtomicLong(java.util.concurrent.atomic.AtomicLong) Block(org.aion.zero.impl.types.Block) BlockDetailsValidator.isValidBlock(org.aion.zero.impl.valid.BlockDetailsValidator.isValidBlock) GenesisStakingBlock(org.aion.zero.impl.types.GenesisStakingBlock) RetValidPreBlock(org.aion.zero.impl.types.RetValidPreBlock) MiningBlock(org.aion.zero.impl.types.MiningBlock) EventBlock(org.aion.evtmgr.impl.evt.EventBlock) StakingBlock(org.aion.zero.impl.types.StakingBlock) HashSet(java.util.HashSet)

Aggregations

Block (org.aion.zero.impl.types.Block)283 MiningBlock (org.aion.zero.impl.types.MiningBlock)155 Test (org.junit.Test)148 AionTransaction (org.aion.base.AionTransaction)106 ImportResult (org.aion.zero.impl.core.ImportResult)86 ArrayList (java.util.ArrayList)63 AionAddress (org.aion.types.AionAddress)61 StakingBlock (org.aion.zero.impl.types.StakingBlock)58 AionBlockSummary (org.aion.zero.impl.types.AionBlockSummary)57 BigInteger (java.math.BigInteger)55 AionRepositoryImpl (org.aion.zero.impl.db.AionRepositoryImpl)34 ByteArrayWrapper (org.aion.util.types.ByteArrayWrapper)30 AionTxReceipt (org.aion.base.AionTxReceipt)29 Hex.toHexString (org.aion.util.conversions.Hex.toHexString)28 AccountState (org.aion.base.AccountState)26 EventBlock (org.aion.evtmgr.impl.evt.EventBlock)26 JSONArray (org.json.JSONArray)26 JSONObject (org.json.JSONObject)26 MiningBlockHeader (org.aion.zero.impl.types.MiningBlockHeader)22 AionTxExecSummary (org.aion.base.AionTxExecSummary)20