Skip to content

Commit

Permalink
vote
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashuaidehao committed Apr 8, 2020
1 parent cfa701c commit cbf59c1
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 19 deletions.
28 changes: 27 additions & 1 deletion neo3-gui/neo3-gui/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,32 @@ public static string SafeSerialize(this ContractParametersContext signContext)
return signContext.ToJson().SerializeJson();
}

/// <summary>
/// create tx by script and signer
/// </summary>
/// <param name="wallet"></param>
/// <param name="script"></param>
/// <param name="signers"></param>
/// <returns></returns>
public static Transaction InitTransaction(this Wallet wallet, byte[] script, params UInt160[] signers)
{
var cosigners = signers.Select(account => new Cosigner { Account = account }).ToArray();
return InitTransaction(wallet, script, cosigners);
}

/// <summary>
/// create tx by script and signer
/// </summary>
/// <param name="wallet"></param>
/// <param name="script"></param>
/// <param name="signers"></param>
/// <returns></returns>
public static Transaction InitTransaction(this Wallet wallet, byte[] script, params Cosigner[] signers)
{
var tx = wallet.MakeTransaction(script, null, null, signers);
return tx;
}


/// <summary>
/// append sign to signContext
Expand Down Expand Up @@ -695,7 +721,7 @@ public static byte[] TryGetPrivateKey(this string privateKey)
}
try
{
return Wallet.GetPrivateKeyFromWIF(privateKey);
return Wallet.GetPrivateKeyFromWIF(privateKey);
}
catch (FormatException)
{
Expand Down
20 changes: 20 additions & 0 deletions neo3-gui/neo3-gui/Models/Contracts/ValidatorModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Neo.Models.Contracts
{
public class ValidatorModel
{
public string Publickey { get; set; }

public string Votes { get; set; }

/// <summary>
/// In Use
/// </summary>
public bool Active { get; set; }
}
}
13 changes: 13 additions & 0 deletions neo3-gui/neo3-gui/Models/Contracts/VoteResultModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Neo.Models.Contracts
{
public class VoteResultModel
{
public UInt256 TxId { get; set; }
}
}
4 changes: 3 additions & 1 deletion neo3-gui/neo3-gui/Models/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ public enum ErrorCode
ExecuteContractFail = 20027,
[Description("Unknown contract. ")]
UnknownContract = 20028,
[Description("Contract already onchain. ")]
[Description("Contract already onchain.")]
ContractAlreadyExist = 20029,
[Description("Validator already exits.")]
ValidatorAlreadyExist = 20030,
}
}
210 changes: 195 additions & 15 deletions neo3-gui/neo3-gui/Services/ApiServices/ContractApiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.IO.Json;
using Neo.Ledger;
Expand All @@ -16,6 +18,7 @@
using Neo.SmartContract.Native;
using Neo.VM;
using Neo.Wallets;
using Neo.Wallets.SQLite;

namespace Neo.Services.ApiServices
{
Expand All @@ -35,7 +38,16 @@ public async Task<object> GetContract(UInt160 contractHash)
return new ContractModel(contract);
}


public async Task<object> GetManifestFile(UInt160 contractHash)
{
using var snapshot = Blockchain.Singleton.GetSnapshot();
var contract = snapshot.Contracts.TryGet(contractHash);
if (contract == null)
{
return Error(ErrorCode.UnknownContract);
}
return contract.Manifest.ToJson();
}


public async Task<object> DeployContract(string nefPath, string manifestPath = null, bool sendTx = false)
Expand All @@ -57,7 +69,7 @@ public async Task<object> DeployContract(string nefPath, string manifestPath = n


using var snapshot = Blockchain.Singleton.GetSnapshot();
var oldContract= snapshot.Contracts.TryGet(nefFile.ScriptHash);
var oldContract = snapshot.Contracts.TryGet(nefFile.ScriptHash);
if (oldContract != null)
{
return Error(ErrorCode.ContractAlreadyExist);
Expand Down Expand Up @@ -137,21 +149,13 @@ public async Task<object> InvokeContract(InvokeContractParameterModel para)
signers.AddRange(para.Cosigners.Select(s => new Cosigner() { Account = s.Account, Scopes = s.Scopes }));
}

Transaction tx = new Transaction
{
Sender = UInt160.Zero,
Attributes = new TransactionAttribute[0],
Witnesses = new Witness[0],
Cosigners = signers.ToArray(),
};
using (ScriptBuilder scriptBuilder = new ScriptBuilder())
{
scriptBuilder.EmitAppCall(para.ContractHash, para.Method, contractParameters);
tx.Script = scriptBuilder.ToArray();
}
Transaction tx = null;
using ScriptBuilder sb = new ScriptBuilder();
sb.EmitAppCall(para.ContractHash, para.Method, contractParameters);

try
{
tx = CurrentWallet.MakeTransaction(tx.Script, null, tx.Attributes, tx.Cosigners);
tx = CurrentWallet.InitTransaction(sb.ToArray(), signers.ToArray());
}
catch (InvalidOperationException)
{
Expand Down Expand Up @@ -189,6 +193,179 @@ public async Task<object> InvokeContract(InvokeContractParameterModel para)
return result;
}


#region Vote


/// <summary>
/// Get all working or candidate validators
/// </summary>
/// <returns></returns>
public async Task<object> GetValidators()
{
using var snapshot = Blockchain.Singleton.GetSnapshot();
var validators = NativeContract.NEO.GetValidators(snapshot);
var registerValidators = NativeContract.NEO.GetRegisteredValidators(snapshot);
return registerValidators.OrderByDescending(v => v.Votes).Select(p => new ValidatorModel
{
Publickey = p.PublicKey.ToString(),
Votes = p.Votes.ToString(),
Active = validators.Contains(p.PublicKey)
}).ToArray();
}




/// <summary>
/// apply for new validator
/// </summary>
/// <param name="pubkey"></param>
/// <returns></returns>
public async Task<object> ApplyForValidator(string pubkey)
{
if (CurrentWallet == null)
{
return Error(ErrorCode.WalletNotOpen);
}
if (pubkey.IsNull())
{
return Error(ErrorCode.ParameterIsNull);
}
ECPoint publicKey = null;
try
{
publicKey = ECPoint.Parse(pubkey, ECCurve.Secp256r1);
}
catch (Exception e)
{
return Error(ErrorCode.InvalidPara);
}
using var snapshot = Blockchain.Singleton.GetSnapshot();
var validators = NativeContract.NEO.GetRegisteredValidators(snapshot);
if (validators.Any(v => v.PublicKey.ToString() == pubkey))
{
return Error(ErrorCode.ValidatorAlreadyExist);
}
VerificationContract contract = new VerificationContract
{
Script = SmartContract.Contract.CreateSignatureRedeemScript(publicKey),
ParameterList = new[] { ContractParameterType.Signature }
};

var account = contract.ScriptHash;
using ScriptBuilder sb = new ScriptBuilder();
sb.EmitAppCall(NativeContract.NEO.Hash, "registerValidator", publicKey);

Transaction tx = null;
try
{
tx = CurrentWallet.InitTransaction(sb.ToArray(), account);
}
catch (InvalidOperationException)
{
return Error(ErrorCode.EngineFault);
}
catch (Exception ex)
{
if (ex.Message.Contains("Insufficient GAS"))
{
return Error(ErrorCode.GasNotEnough);
}
throw;
}

var (signSuccess, context) = CurrentWallet.TrySignTx(tx);
if (!signSuccess)
{
return Error(ErrorCode.SignFail, context.SafeSerialize());
}
var result = new VoteResultModel();
await tx.Broadcast();
result.TxId = tx.Hash;
return result;
}




/// <summary>
/// vote for consensus node
/// </summary>
/// <returns></returns>
public async Task<object> VoteCN(UInt160 account, string[] pubkeys)
{
if (CurrentWallet == null)
{
return Error(ErrorCode.WalletNotOpen);
}
if (account == null || pubkeys.IsEmpty())
{
return Error(ErrorCode.ParameterIsNull);
}
ECPoint[] publicKeys = null;
try
{
publicKeys = pubkeys.Select(p => ECPoint.Parse(p, ECCurve.Secp256r1)).ToArray();
}
catch (Exception e)
{
return Error(ErrorCode.InvalidPara);
}
using ScriptBuilder sb = new ScriptBuilder();
sb.EmitAppCall(NativeContract.NEO.Hash, "vote", new ContractParameter
{
Type = ContractParameterType.Hash160,
Value = account
}, new ContractParameter
{
Type = ContractParameterType.Array,
Value = publicKeys.Select(p => new ContractParameter
{
Type = ContractParameterType.PublicKey,
Value = p
}).ToArray()
});

Transaction tx = null;
try
{
tx = CurrentWallet.InitTransaction(sb.ToArray(), account);
}
catch (InvalidOperationException)
{
return Error(ErrorCode.EngineFault);
}
catch (Exception ex)
{
if (ex.Message.Contains("Insufficient GAS"))
{
return Error(ErrorCode.GasNotEnough);
}
throw;
}

var (signSuccess, context) = CurrentWallet.TrySignTx(tx);
if (!signSuccess)
{
return Error(ErrorCode.SignFail, context.SafeSerialize());
}
var result = new VoteResultModel();
await tx.Broadcast();
result.TxId = tx.Hash;
return result;
}


#endregion





#region Private


/// <summary>
/// try to read nef file
/// </summary>
Expand Down Expand Up @@ -265,5 +442,8 @@ private async Task CheckBadOpcode(byte[] script)
context.InstructionPointer += ci.Size;
}
}


#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public async Task<object> GetTransaction(UInt256 txId)
model.Transfers = trans.Select(tx => tx.ToTransferModel()).ToList();

var executeResult = db.GetExecuteLog(txId);
if (executeResult.Notifications.NotEmpty())
if (executeResult?.Notifications.NotEmpty() == true)
{
model.Notifies.AddRange(
executeResult.Notifications.Select(n => new NotifyModel()
Expand Down Expand Up @@ -103,7 +103,7 @@ public async Task<object> QueryTransactions(int pageIndex = 1, int limit = 100,
}




/// <summary>
/// query all nep transactions(on chain)
Expand Down
19 changes: 19 additions & 0 deletions neo3-gui/neo3-gui/Services/ApiServices/WalletApiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,25 @@ public async Task<object> ListPublicKey(int count = 100)
});
}


/// <summary>
/// list current wallet candidate address(only single sign address)
/// </summary>
/// <returns></returns>
public async Task<object> ListCandidatePublicKey(int count = 100)
{
if (CurrentWallet == null)
{
return Error(ErrorCode.WalletNotOpen);
}
var accounts = CurrentWallet.GetAccounts().Where(a => !a.WatchOnly && a.Contract.Script.IsSignatureContract()).Take(count).ToList();
return accounts.Select(a => new PublicKeyModel
{
Address = a.Address,
PublicKey = a.GetKey().PublicKey.EncodePoint(true),
});
}

/// <summary>
/// import watch only addresses
/// </summary>
Expand Down

0 comments on commit cbf59c1

Please sign in to comment.