public void ExecuteWithInsufficientBalance() { var balance = ImmutableDictionary <(Address, Currency), FungibleAssetValue> .Empty .Add((_sender, _currency), _currency * 1000) .Add((_recipient, _currency), _currency * 10); var prevState = new State( balance: balance ); var action = new TransferAsset( sender: _sender, recipient: _recipient, amount: _currency * 100000 ); Assert.Throws <InsufficientBalanceException>(() => { action.Execute(new ActionContext() { PreviousStates = prevState, Signer = _sender, Rehearsal = false, BlockIndex = 1, }); }); }
public void Execute() { var balance = ImmutableDictionary <(Address, Currency), FungibleAssetValue> .Empty .Add((_sender, _currency), _currency * 1000) .Add((_recipient, _currency), _currency * 10); var prevState = new State( balance: balance ); var action = new TransferAsset( sender: _sender, recipient: _recipient, amount: _currency * 100 ); IAccountStateDelta nextState = action.Execute(new ActionContext() { PreviousStates = prevState, Signer = _sender, Rehearsal = false, BlockIndex = 1, }); Assert.Equal(_currency * 900, nextState.GetBalance(_sender, _currency)); Assert.Equal(_currency * 110, nextState.GetBalance(_recipient, _currency)); }
public void ExecuteWithMinterAsRecipient() { var currencyByRecipient = new Currency("NCG", 2, _sender); var balance = ImmutableDictionary <(Address, Currency), FungibleAssetValue> .Empty .Add((_sender, currencyByRecipient), _currency * 1000) .Add((_recipient, currencyByRecipient), _currency * 10); var prevState = new State( balance: balance ); var action = new TransferAsset( sender: _sender, recipient: _recipient, amount: currencyByRecipient * 100 ); var ex = Assert.Throws <InvalidTransferMinterException>(() => { action.Execute(new ActionContext() { PreviousStates = prevState, Signer = _sender, Rehearsal = false, BlockIndex = 1, }); }); Assert.Equal(new[] { _sender }, ex.Minters); Assert.Equal(_sender, ex.Sender); Assert.Equal(_recipient, ex.Recipient); }
public void TransferAsset( [Argument("SENDER", Description = "An address of sender.")] string sender, [Argument("RECIPIENT", Description = "An address of recipient.")] string recipient, [Argument("AMOUNT", Description = "An amount of gold to transfer.")] int goldAmount, [Argument("GENESIS-BLOCK", Description = "A genesis block containing InitializeStates.")] string genesisBlock ) { Block <NCAction> genesis = Block <NCAction> .Deserialize(File.ReadAllBytes(genesisBlock)); var initStates = (InitializeStates)genesis.Transactions.Single().Actions.Single().InnerAction; Currency currency = new GoldCurrencyState(initStates.GoldCurrency).Currency; var action = new TransferAsset( new Address(sender), new Address(recipient), currency * goldAmount ); var bencoded = new List( new IValue[] { (Text)nameof(TransferAsset), action.PlainValue } ); byte[] raw = _codec.Encode(bencoded); Console.Write(ByteUtil.Hex(raw)); }
public void TransferAsset( [Argument("SENDER", Description = "An address of sender.")] string sender, [Argument("RECIPIENT", Description = "An address of recipient.")] string recipient, [Argument("AMOUNT", Description = "An amount of gold to transfer.")] int goldAmount, [Argument("GENESIS-BLOCK", Description = "A genesis block containing InitializeStates.")] string genesisBlock ) { byte[] genesisBytes = File.ReadAllBytes(genesisBlock); var genesisDict = (Bencodex.Types.Dictionary)_codec.Decode(genesisBytes); IReadOnlyList <Transaction <NCAction> > genesisTxs = BlockMarshaler.UnmarshalBlockTransactions <NCAction>(genesisDict); var initStates = (InitializeStates)genesisTxs.Single().Actions.Single().InnerAction; Currency currency = new GoldCurrencyState(initStates.GoldCurrency).Currency; var action = new TransferAsset( new Address(sender), new Address(recipient), currency * goldAmount ); var bencoded = new List( (Text)nameof(TransferAsset), action.PlainValue ); byte[] raw = _codec.Encode(bencoded); Console.Write(ByteUtil.Hex(raw)); }
public async Task TransferNCGHistories() { PrivateKey minerPrivateKey = new PrivateKey(); Address sender = minerPrivateKey.ToAddress(), recipient = new PrivateKey().ToAddress(); await BlockChain.MineBlock(sender); await BlockChain.MineBlock(recipient); var currency = new GoldCurrencyState((Dictionary)BlockChain.GetState(Addresses.GoldCurrency)).Currency; var transferAsset = new TransferAsset(sender, recipient, new FungibleAssetValue(currency, 10, 0)); var tx = BlockChain.MakeTransaction(minerPrivateKey, new PolymorphicAction <ActionBase>[] { transferAsset }); var block = await BlockChain.MineBlock(minerPrivateKey.ToAddress(), append : false); BlockChain.Append(block); Assert.NotNull(StandaloneContextFx.Store?.GetTxExecution(block.Hash, tx.Id)); var blockHashHex = ByteUtil.Hex(block.Hash.ToByteArray()); var result = await ExecuteQueryAsync( $"{{ transferNCGHistories(blockHash: \"{blockHashHex}\") {{ blockHash txId sender recipient amount }} }}"); Assert.Null(result.Errors); Assert.Equal(new List <object> { new Dictionary <string, object> { ["blockHash"] = block.Hash.ToString(), ["txId"] = tx.Id.ToString(), ["sender"] = transferAsset.Sender.ToString(), ["recipient"] = transferAsset.Recipient.ToString(), ["amount"] = transferAsset.Amount.GetQuantityString(), } }, result.Data.As <Dictionary <string, object> >()["transferNCGHistories"]); }
public void ExecuteWithUnactivatedRecipient() { var activatedAddress = new ActivatedAccountsState().AddAccount(new PrivateKey().ToAddress()); var balance = ImmutableDictionary <(Address, Currency), FungibleAssetValue> .Empty .Add((_sender, _currency), _currency * 1000) .Add((_recipient, _currency), _currency * 10); var state = ImmutableDictionary <Address, IValue> .Empty .Add(_sender.Derive(ActivationKey.DeriveKey), true.Serialize()) .Add(Addresses.ActivatedAccount, activatedAddress.Serialize()); var prevState = new State( state: state, balance: balance ); var action = new TransferAsset( sender: _sender, recipient: _recipient, amount: _currency * 100 ); var ex = Assert.Throws <InvalidTransferUnactivatedRecipientException>(() => { action.Execute(new ActionContext() { PreviousStates = prevState, Signer = _sender, Rehearsal = false, BlockIndex = 1, }); }); Assert.Equal(_sender, ex.Sender); Assert.Equal(_recipient, ex.Recipient); }
public void ExecuteWithInvalidSigner() { var balance = ImmutableDictionary <(Address, Currency), FungibleAssetValue> .Empty .Add((_sender, _currency), _currency * 1000) .Add((_recipient, _currency), _currency * 10); var prevState = new State( balance: balance ); var action = new TransferAsset( sender: _sender, recipient: _recipient, amount: _currency * 100 ); var exc = Assert.Throws <InvalidTransferSignerException>(() => { _ = action.Execute(new ActionContext() { PreviousStates = prevState, // 송금자가 직접 사인하지 않으면 실패해야 합니다. Signer = _recipient, Rehearsal = false, BlockIndex = 1, }); }); Assert.Equal(exc.Sender, _sender); Assert.Equal(exc.Recipient, _recipient); Assert.Equal(exc.TxSigner, _recipient); }
public TransferAssetDto GetTransferAssetForEdit(int id) { TransferAsset transferAssets = repository.GetAll() .Where(item => !item.IsDelete) .SingleOrDefault(item => item.Id == id); return(ObjectMapper.Map <TransferAssetDto>(transferAssets)); }
public TransferAssetDto CreateTransferAsset(TransferAssetDto input) { TransferAsset transferAsset = ObjectMapper.Map <TransferAsset>(input); SetAuditInsert(transferAsset); _ = repository.Insert(transferAsset); CurrentUnitOfWork.SaveChanges(); return(input); }
public static Payload MakeTransferPayload(string sender, string recipient, long amount) { var transfer = new TransferAsset { Sender = sender.FromHexString(), Recipient = recipient.FromHexString(), Amount = amount }; return(TransactionFactory.MakePayload(transfer, PayloadType.TransferAsset)); }
private void ProcessTransferAsset(TransferAsset transferAsset) { _clientCryptoService.DecodeEcdhTuple(transferAsset.TransferredAsset.EcdhTuple, null, out byte[] blindingFactor, out byte[] assetId); AttributeType attributeType = _assetsService.GetAttributeType(assetId); _dataAccessService.StoreSpAttribute(_accountId, attributeType, assetId, transferAsset.Signer.Value.ToHexString(), blindingFactor, transferAsset.TransferredAsset.AssetCommitment, transferAsset.SurjectionProof.AssetCommitments[0]); _idenitiesHubContext.Clients.Group(_accountId.ToString(CultureInfo.InvariantCulture)).SendAsync("PushAttribute", new SpAttributeDto { AttributeType = attributeType.ToString(), Source = transferAsset.Signer.ArraySegment.Array.ToHexString(), AssetId = assetId.ToHexString(), OriginalBlindingFactor = blindingFactor.ToHexString(), OriginalCommitment = transferAsset.TransferredAsset.AssetCommitment.ToHexString(), IssuingCommitment = transferAsset.SurjectionProof.AssetCommitments[0].ToHexString(), Validated = false, IsOverriden = false }); }
public void Rehearsal() { var action = new TransferAsset( sender: _sender, recipient: _recipient, amount: _currency * 100 ); IAccountStateDelta nextState = action.Execute(new ActionContext() { PreviousStates = new State(ImmutableDictionary <Address, IValue> .Empty), Signer = default,
public ListResultDto <TransferAssetDto> GetTransferAssetByCode(string code) { code = code.ToLower(); TransferAsset transferAsset = repository.GetAll() .Where(item => item.AssetCode.ToLower() == code) .SingleOrDefault(); System.Collections.Generic.List <TransferAssetDto> transferAssets = new System.Collections.Generic.List <TransferAssetDto> { ObjectMapper.Map <TransferAssetDto>(transferAsset) }; return(new ListResultDto <TransferAssetDto>(transferAssets)); }
public void DeleteTransferAsset(int id) { TransferAsset transferAsset = repository.GetAll() .Where(item => !item.IsDelete) .SingleOrDefault(item => item.Id == id); if (transferAsset != null) { transferAsset.IsDelete = true; repository.Update(transferAsset); CurrentUnitOfWork.SaveChanges(); } }
public int TransferAsset( [Argument("SENDER-ADDRESS", Description = "A hex-encoded sender address.")] string senderAddress, [Argument("RECIPIENT-ADDRESS", Description = "A hex-encoded recipient address.")] string recipientAddress, [Argument("AMOUNT", Description = "The amount of asset to transfer.")] string amount, [Argument("PATH", Description = "A file path of base64 encoded action.")] string?filePath = null, [Argument("MEMO", Description = "A memo of asset transfer")] string?memo = null ) { try { filePath ??= Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); // Minter for 9c-mainnet var currency = new Currency("NCG", 2, minter: new Address("47d082a115c63e7b58b1532d20e631538eafadde")); FungibleAssetValue amountFungibleAssetValue = FungibleAssetValue.Parse(currency, amount); Address sender = new Address(ByteUtil.ParseHex(senderAddress)); Address recipient = new Address(ByteUtil.ParseHex(recipientAddress)); Nekoyume.Action.TransferAsset action = new TransferAsset( sender, recipient, amountFungibleAssetValue, memo); var encoded = new List( new[] { (Text)nameof(Nekoyume.Action.TransferAsset), action.PlainValue } ); byte[] raw = Codec.Encode(encoded); File.WriteAllText(filePath, Convert.ToBase64String(raw)); Console.Write(Convert.ToBase64String(raw)); return(0); } catch (Exception e) { _console.Error.WriteLine(e); return(-1); } }
public TransferAssetDto UpdateTransferAsset(TransferAssetDto input) { TransferAsset transferAsset = repository .GetAll() .Where(item => !item.IsDelete) .SingleOrDefault(item => item.Id == input.Id); if (transferAsset is null) { return(null); } else { ObjectMapper.Map(input, transferAsset); SetAuditEdit(transferAsset); transferAsset = repository.Update(transferAsset); CurrentUnitOfWork.SaveChanges(); return(ObjectMapper.Map <TransferAssetDto>(transferAsset)); } }
public void ExecuteWithInvalidRecipient() { var balance = ImmutableDictionary <(Address, Currency), FungibleAssetValue> .Empty .Add((_sender, _currency), _currency * 1000); var prevState = new State( balance: balance ); // Should not allow TransferAsset with same sender and recipient. var action = new TransferAsset( sender: _sender, recipient: _sender, amount: _currency * 100 ); // No exception should be thrown when its index is less then 380000. _ = action.Execute(new ActionContext() { PreviousStates = prevState, Signer = _sender, Rehearsal = false, BlockIndex = 1, }); var exc = Assert.Throws <InvalidTransferRecipientException>(() => { _ = action.Execute(new ActionContext() { PreviousStates = prevState, Signer = _sender, Rehearsal = false, BlockIndex = 380001, }); }); Assert.Equal(exc.Sender, _sender); Assert.Equal(exc.Recipient, _sender); }
public void TransferAsset( int amount, int expectedCode, string?memo = null) { var senderPrivateKey = new PrivateKey(); var recipientPrivateKey = new PrivateKey(); var filePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); var resultCode = _command.TransferAsset( senderPrivateKey.ToAddress().ToHex(), recipientPrivateKey.ToAddress().ToHex(), Convert.ToString(amount), filePath, memo); Assert.Equal(expectedCode, resultCode); if (resultCode == 0) { var rawAction = Convert.FromBase64String(File.ReadAllText(filePath)); var decoded = (List)_codec.Decode(rawAction); string type = (Text)decoded[0]; Assert.Equal(nameof(Nekoyume.Action.TransferAsset), type); Dictionary plainValue = (Dictionary)decoded[1]; var action = new TransferAsset(); action.LoadPlainValue(plainValue); Assert.Equal(memo, action.Memo); Assert.Equal(amount, action.Amount.MajorUnit); Assert.Equal(senderPrivateKey.ToAddress(), action.Sender); Assert.Equal(recipientPrivateKey.ToAddress(), action.Recipient); } else { Assert.Contains("System.FormatException: Could not find any recognizable digits.", _console.Error.ToString()); } }
public async Task MixedMiningPolicy() { var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; var authorizedMinerKey = new PrivateKey(); var permissionedMinerKey = new PrivateKey(); var someMinerKey = new PrivateKey(); var addresses = new Address[] { authorizedMinerKey.ToAddress(), permissionedMinerKey.ToAddress(), someMinerKey.ToAddress(), }; var pendingActivations = new[] { authorizedMinerKey, permissionedMinerKey, someMinerKey, }.Select(key => ActivationKey.Create(key, nonce).Item2).ToArray(); var action = new TransferAsset( new PrivateKey().ToAddress(), new PrivateKey().ToAddress(), new FungibleAssetValue(_currency, 0, 0)); // This creates genesis with _privateKey as its miner. Block <PolymorphicAction <ActionBase> > genesis = MakeGenesisBlock( default(Address), ImmutableHashSet <Address> .Empty, pendingActivations: pendingActivations); using var store = new DefaultStore(null); using var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var blockPolicySource = new BlockPolicySource(Logger.None); var blockChain = new BlockChain <PolymorphicAction <ActionBase> >( blockPolicySource.GetPolicy( minimumDifficulty: 10_000, hashAlgorithmTypePolicy: null, maxBlockBytesPolicy: null, minTransactionsPerBlockPolicy: null, maxTransactionsPerBlockPolicy: null, maxTransactionsPerSignerPerBlockPolicy: null, authorizedMinersPolicy: AuthorizedMinersPolicy .Default .Add(new SpannedSubPolicy <ImmutableHashSet <Address> >( startIndex: 0, endIndex: 6, filter: index => index % 2 == 0, value: new Address[] { authorizedMinerKey.ToAddress() } .ToImmutableHashSet())), permissionedMinersPolicy: PermissionedMinersPolicy .Default .Add(new SpannedSubPolicy <ImmutableHashSet <Address> >( startIndex: 2, endIndex: 10, filter: index => index % 3 == 0, value: new Address[] { permissionedMinerKey.ToAddress() } .ToImmutableHashSet()))), new VolatileStagePolicy <PolymorphicAction <ActionBase> >(), store, stateStore, genesis, renderers: new[] { blockPolicySource.BlockRenderer } ); Transaction <PolymorphicAction <ActionBase> > proof; // Index 1: Anyone can mine. await blockChain.MineBlock(someMinerKey); // Index 2: Only authorized miner can mine. await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(permissionedMinerKey)); await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(someMinerKey)); await blockChain.MineBlock(authorizedMinerKey); // Index 3: Only permissioned miner can mine. await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(authorizedMinerKey)); await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(someMinerKey)); await blockChain.MineBlock(permissionedMinerKey); // Index 4: Only authorized miner can mine. await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(permissionedMinerKey)); await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(someMinerKey)); await blockChain.MineBlock(authorizedMinerKey); // Index 5: Anyone can mine again. await blockChain.MineBlock(someMinerKey); // Index 6: In case both authorized mining and permissioned mining apply, // only authorized miner can mine. await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(permissionedMinerKey)); await blockChain.MineBlock(authorizedMinerKey); // Index 7, 8, 9: Check authorized mining ended. await blockChain.MineBlock(someMinerKey); await blockChain.MineBlock(someMinerKey); await Assert.ThrowsAsync <BlockPolicyViolationException>( () => blockChain.MineBlock(someMinerKey)); proof = blockChain.MakeTransaction( permissionedMinerKey, new PolymorphicAction <ActionBase>[] { action }); await blockChain.MineBlock(permissionedMinerKey); // Index 10, 11, 12: Check permissioned mining ended. await blockChain.MineBlock(someMinerKey); await blockChain.MineBlock(someMinerKey); await blockChain.MineBlock(someMinerKey); // Index 13, 14: Check authorized miner and permissioned miner can also mine // when policy is allowed for all miners. await blockChain.MineBlock(authorizedMinerKey); await blockChain.MineBlock(permissionedMinerKey); }
public async Task Transfer(string?memo, bool error) { NineChroniclesNodeService service = StandaloneContextFx.NineChroniclesNodeService !; Currency goldCurrency = new GoldCurrencyState( (Dictionary)BlockChain.GetState(GoldCurrencyState.Address) ).Currency; Address senderAddress = service.MinerPrivateKey !.ToAddress(); var store = service.Store; await BlockChain.MineBlock(senderAddress); await BlockChain.MineBlock(senderAddress); // 10 + 10 (mining rewards) Assert.Equal( 20 * goldCurrency, BlockChain.GetBalance(senderAddress, goldCurrency) ); Address recipient = new PrivateKey().ToAddress(); long txNonce = BlockChain.GetNextTxNonce(senderAddress); var args = $"recipient: \"{recipient}\", txNonce: {txNonce}, amount: \"17.5\""; if (!(memo is null)) { args += $"memo: \"{memo}\""; } var query = $"mutation {{ transfer({args}) }}"; ExecutionResult result = await ExecuteQueryAsync(query); if (error) { Assert.NotNull(result.Errors); } else { Assert.Null(result.Errors); var stagedTxIds = BlockChain.GetStagedTransactionIds().ToImmutableList(); Assert.Single(stagedTxIds); string transferTxIdString = stagedTxIds.Single().ToString(); TxId transferTxId = new TxId(ByteUtil.ParseHex(transferTxIdString)); Transaction <NCAction>?tx = BlockChain.StagePolicy.Get(BlockChain, transferTxId, false); Assert.NotNull(tx); Assert.IsType <TransferAsset>(tx !.Actions.Single().InnerAction); TransferAsset transferAsset = (TransferAsset)tx.Actions.Single().InnerAction; Assert.Equal(memo, transferAsset.Memo); var expectedResult = new Dictionary <string, object> { ["transfer"] = transferTxIdString, }; Assert.Equal(expectedResult, result.Data); await BlockChain.MineBlock(recipient); // 10 + 10 - 17.5(transfer) Assert.Equal( FungibleAssetValue.Parse(goldCurrency, "2.5"), BlockChain.GetBalance(senderAddress, goldCurrency) ); // 0 + 17.5(transfer) + 10(mining reward) Assert.Equal( FungibleAssetValue.Parse(goldCurrency, "27.5"), BlockChain.GetBalance(recipient, goldCurrency) ); } }
protected override Memory <byte> ParseTransactionalTransitional(ushort version, Memory <byte> spanBody, out TransactionalTransitionalPacketBase transactionalBlockBase) { TransferAsset block = null; if (version == 1) { int readBytes = 0; byte[] assetCommitment = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray(); readBytes += Globals.NODE_PUBLIC_KEY_SIZE; byte[] assetId = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray(); readBytes += Globals.NODE_PUBLIC_KEY_SIZE; byte[] mask = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray(); readBytes += Globals.NODE_PUBLIC_KEY_SIZE; ushort assetCommitmentsCount = BinaryPrimitives.ReadUInt16LittleEndian(spanBody.Slice(readBytes).Span); readBytes += sizeof(ushort); byte[][] assetCommitments = new byte[assetCommitmentsCount][]; for (int i = 0; i < assetCommitmentsCount; i++) { assetCommitments[i] = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray(); readBytes += Globals.NODE_PUBLIC_KEY_SIZE; } byte[] e = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray(); readBytes += Globals.NODE_PUBLIC_KEY_SIZE; byte[][] s = new byte[assetCommitmentsCount][]; for (int i = 0; i < assetCommitmentsCount; i++) { s[i] = spanBody.Slice(readBytes, Globals.NODE_PUBLIC_KEY_SIZE).ToArray(); readBytes += Globals.NODE_PUBLIC_KEY_SIZE; } block = new TransferAsset { TransferredAsset = new EncryptedAsset { AssetCommitment = assetCommitment, EcdhTuple = new EcdhTupleCA { AssetId = assetId, Mask = mask } }, SurjectionProof = new SurjectionProof { AssetCommitments = assetCommitments, Rs = new BorromeanRingSignature { E = e, S = s } } }; transactionalBlockBase = block; return(spanBody.Slice(readBytes)); } throw new BlockVersionNotSupportedException(version, BlockType); }