Search in sources :

Example 1 with StakingBlock

use of org.aion.zero.impl.types.StakingBlock 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 2 with StakingBlock

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

the class AionImpl method getStakingBlockTemplate.

// Returns null if we're waiting on a Mining block, or if creating a new block template failed for some reason
@Override
public StakingBlock getStakingBlockTemplate(byte[] newSeed, byte[] signingPublicKey, byte[] coinbase) {
    lock.lock();
    try {
        Block best = getBlockchain().getBestBlock();
        LOG_GEN.debug("getStakingBlockTemplate best:{}", best);
        if (best.getHeader().getSealType() == Seal.PROOF_OF_STAKE) {
            return null;
        } else {
            return getBlockchain().createStakingBlockTemplate(best, getAionHub().getPendingState().getPendingTransactions(), signingPublicKey, newSeed, coinbase);
        }
    } finally {
        lock.unlock();
    }
}
Also used : StakingBlock(org.aion.zero.impl.types.StakingBlock) Block(org.aion.zero.impl.types.Block)

Example 3 with StakingBlock

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

the class BlockchainTestUtils method addStakingBlock.

public static Pair<Block, ImportResult> addStakingBlock(StandaloneBlockchain chain, Block parent, List<AionTransaction> txs, ECKey key) {
    byte[] parentSeed = chain.forkUtility.isUnityForkBlock(parent.getNumber()) ? StakingBlockHeader.GENESIS_SEED : ((StakingBlock) chain.getBlockByHash(parent.getParentHash())).getSeed();
    byte[] newSeed = key.sign(parentSeed).getSignature();
    StakingBlock block = chain.createStakingBlockTemplate(parent, txs, key.getPubKey(), newSeed, new AionAddress(key.getAddress()).toByteArray());
    if (block == null) {
        return null;
    }
    byte[] mineHashSig = key.sign(block.getHeader().getMineHash()).getSignature();
    block.seal(mineHashSig, key.getPubKey());
    ImportResult result = chain.tryToConnect(block);
    System.out.format("Created block with hash: %s, number: %6d, extra data: %6s, txs: %3d, import status: %20s %n", block.getShortHash(), block.getNumber(), new String(block.getExtraData()), block.getTransactionsList().size(), result.toString());
    return Pair.of(block, result);
}
Also used : AionAddress(org.aion.types.AionAddress) ImportResult(org.aion.zero.impl.core.ImportResult) StakingBlock(org.aion.zero.impl.types.StakingBlock)

Example 4 with StakingBlock

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

the class BlockchainTestUtils method generateNextStakingBlock.

/**
 * Generates a single staking block (containing the given transactions) on top of the given chain.
 * Does not import the block.
 *
 * @param chain blockchain implementation to be extended with the new block
 * @param parent the parent for the block to be generated
 * @param transactions list of transactions to be included in the block
 * @param producer the staker key that will create and sign the block
 * @return the generated block
 */
public static Block generateNextStakingBlock(StandaloneBlockchain chain, Block parent, List<AionTransaction> transactions, ECKey producer) {
    // get the parent seed
    byte[] parentSeed = chain.forkUtility.isUnityForkBlock(parent.getNumber()) ? StakingBlockHeader.GENESIS_SEED : ((StakingBlock) chain.getBlockByHash(parent.getParentHash())).getSeed();
    // SignatureSchemeSwap check
    byte[] newSeedOrProof;
    if (chain.forkUtility.isSignatureSwapForkBlock(parent.getNumber() - 1)) {
        newSeedOrProof = VRF_Ed25519.generateProof(parentSeed, producer.getPrivKeyBytes());
    } else if (chain.forkUtility.isSignatureSwapForkActive(parent.getNumber() + 1)) {
        byte[] hash = VRF_Ed25519.generateProofHash(parentSeed);
        newSeedOrProof = VRF_Ed25519.generateProof(hash, producer.getPrivKeyBytes());
    } else {
        newSeedOrProof = producer.sign(parentSeed).getSignature();
    }
    // create staking block
    StakingBlock block = chain.createStakingBlockTemplate(parent, transactions, producer.getPubKey(), newSeedOrProof, new AionAddress(producer.getAddress()).toByteArray());
    if (block == null) {
        return null;
    }
    // seal staking block
    byte[] mineHashSig = producer.sign(block.getHeader().getMineHash()).getSignature();
    block.seal(mineHashSig, producer.getPubKey());
    return block;
}
Also used : AionAddress(org.aion.types.AionAddress) StakingBlock(org.aion.zero.impl.types.StakingBlock)

Example 5 with StakingBlock

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

the class ApiAion0 method getRsp_getBlockDetails.

private List<Message.t_BlockDetail> getRsp_getBlockDetails(List<Block> blks) {
    return blks.parallelStream().filter(Objects::nonNull).map(blk -> {
        Message.t_BlockDetail.Builder builder;
        if (blk.getHeader().getSealType() == Seal.PROOF_OF_WORK) {
            MiningBlock b = (MiningBlock) blk;
            builder = Message.t_BlockDetail.newBuilder().setBlockNumber(b.getNumber()).setDifficulty(ByteString.copyFrom(b.getDifficulty())).setExtraData(ByteString.copyFrom(b.getExtraData())).setHash(ByteString.copyFrom(b.getHash())).setLogsBloom(ByteString.copyFrom(b.getLogBloom())).setMinerAddress(ByteString.copyFrom(b.getCoinbase().toByteArray())).setNonce(ByteString.copyFrom(b.getNonce())).setNrgConsumed(b.getNrgConsumed()).setNrgLimit(b.getNrgLimit()).setParentHash(ByteString.copyFrom(b.getParentHash())).setTimestamp(b.getTimestamp()).setTxTrieRoot(ByteString.copyFrom(b.getTxTrieRoot())).setReceiptTrieRoot(ByteString.copyFrom(b.getReceiptsRoot())).setStateRoot(ByteString.copyFrom(b.getStateRoot())).setSize(b.size()).setSolution(ByteString.copyFrom(b.getHeader().getSolution())).setTotalDifficulty(ByteString.copyFrom(blk.getTotalDifficulty().toByteArray()));
        } else if (blk.getHeader().getSealType() == Seal.PROOF_OF_STAKE) {
            StakingBlock b = (StakingBlock) blk;
            builder = Message.t_BlockDetail.newBuilder().setBlockNumber(b.getNumber()).setDifficulty(ByteString.copyFrom(b.getDifficulty())).setExtraData(ByteString.copyFrom(b.getExtraData())).setHash(ByteString.copyFrom(b.getHash())).setLogsBloom(ByteString.copyFrom(b.getLogBloom())).setMinerAddress(ByteString.copyFrom(b.getCoinbase().toByteArray())).setNonce(ByteString.copyFrom(new byte[0])).setNrgConsumed(b.getNrgConsumed()).setNrgLimit(b.getNrgLimit()).setParentHash(ByteString.copyFrom(b.getParentHash())).setTimestamp(b.getTimestamp()).setTxTrieRoot(ByteString.copyFrom(b.getTxTrieRoot())).setReceiptTrieRoot(ByteString.copyFrom(b.getReceiptsRoot())).setStateRoot(ByteString.copyFrom(b.getStateRoot())).setSize(b.size()).setSolution(ByteString.copyFrom(new byte[0])).setTotalDifficulty(ByteString.copyFrom(blk.getTotalDifficulty().toByteArray()));
        } else {
            throw new IllegalStateException("Invalid block type!");
        }
        List<AionTransaction> txs = blk.getTransactionsList();
        List<Message.t_TxDetail> tds = txs.parallelStream().filter(Objects::nonNull).map((AionTransaction tx) -> {
            AionTxInfo ti = ((AionBlockchainImpl) this.ac.getAionHub().getBlockchain()).getTransactionInfoLite(tx.getTransactionHash(), blk.getHeader().getHash());
            List<Message.t_LgEle> tles = ti.getReceipt().getLogInfoList().parallelStream().map(log -> {
                List<String> topics = new ArrayList<>();
                for (int i = 0; i < log.copyOfTopics().size(); i++) {
                    topics.add(StringUtils.toJsonHex(log.copyOfTopics().get(i)));
                }
                return Message.t_LgEle.newBuilder().setData(ByteString.copyFrom(log.copyOfData())).setAddress(ByteString.copyFrom(log.copyOfAddress())).addAllTopics(topics).build();
            }).filter(Objects::nonNull).collect(Collectors.toList());
            Message.t_TxDetail.Builder tdBuilder = Message.t_TxDetail.newBuilder().setData(ByteString.copyFrom(tx.getData())).setTo(ByteString.copyFrom(tx.getDestinationAddress() == null ? EMPTY_BYTE_ARRAY : tx.getDestinationAddress().toByteArray())).setFrom(ByteString.copyFrom(tx.getSenderAddress().toByteArray())).setNonce(ByteString.copyFrom(tx.getNonce())).setValue(ByteString.copyFrom(tx.getValue())).setNrgConsumed(ti.getReceipt().getEnergyUsed()).setNrgPrice(tx.getEnergyPrice()).setTxHash(ByteString.copyFrom(tx.getTransactionHash())).setTxIndex(ti.getIndex()).setType(ByteString.copyFrom(new byte[] { tx.getType() })).addAllLogs(tles);
            return tdBuilder.build();
        }).filter(Objects::nonNull).collect(Collectors.toList());
        return builder.addAllTx(tds).build();
    }).filter(Objects::nonNull).collect(Collectors.toList());
}
Also used : AionTxInfo(org.aion.zero.impl.types.AionTxInfo) ArrayList(java.util.ArrayList) AionTransaction(org.aion.base.AionTransaction) ByteString(com.google.protobuf.ByteString) MiningBlock(org.aion.zero.impl.types.MiningBlock) AionBlockchainImpl(org.aion.zero.impl.blockchain.AionBlockchainImpl) StakingBlock(org.aion.zero.impl.types.StakingBlock)

Aggregations

StakingBlock (org.aion.zero.impl.types.StakingBlock)18 MiningBlock (org.aion.zero.impl.types.MiningBlock)10 Block (org.aion.zero.impl.types.Block)7 AionAddress (org.aion.types.AionAddress)6 BigInteger (java.math.BigInteger)4 AionTransaction (org.aion.base.AionTransaction)4 EventBlock (org.aion.evtmgr.impl.evt.EventBlock)4 GenesisStakingBlock (org.aion.zero.impl.types.GenesisStakingBlock)4 RetValidPreBlock (org.aion.zero.impl.types.RetValidPreBlock)4 BlockDetailsValidator.isValidBlock (org.aion.zero.impl.valid.BlockDetailsValidator.isValidBlock)4 JSONObject (org.json.JSONObject)4 ArrayList (java.util.ArrayList)3 AionBlockchainImpl (org.aion.zero.impl.blockchain.AionBlockchainImpl)3 AccountState (org.aion.base.AccountState)2 ImportResult (org.aion.zero.impl.core.ImportResult)2 AionTxInfo (org.aion.zero.impl.types.AionTxInfo)2 StakingBlockHeader (org.aion.zero.impl.types.StakingBlockHeader)2 JSONArray (org.json.JSONArray)2 ByteString (com.google.protobuf.ByteString)1 ArrayDeque (java.util.ArrayDeque)1