Skip to content

Commit

Permalink
Merge pull request #769 from AElfProject/improve-proposal
Browse files Browse the repository at this point in the history
Improve proposal
  • Loading branch information
rosona authored Jan 22, 2019
2 parents a3b6cee + 0c6c7fd commit 0f4a0a6
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 54 deletions.
2 changes: 1 addition & 1 deletion AElf.Configuration/Config/Chain/chain.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"ChainId": "aelf"
"ChainId": "AELF"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
Expand All @@ -14,6 +14,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.frameworks.autofac" Version="0.1.0" />
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
Expand Down
101 changes: 53 additions & 48 deletions AElf.Contracts.Authorization/AuthorizationContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public Proposal GetProposal(Hash proposalHash)
else
{
var msigAccount = proposal.MultiSigAccount;
var auth = GetAuth(msigAccount);
var auth = GetAuthorization(msigAccount);
Api.Assert(!auth.Equals(new Kernel.Authorization()), "Not found authorization."); // this should not happen.

// check approvals
Expand All @@ -110,9 +110,36 @@ public Proposal GetProposal(Hash proposalHash)
? ProposalStatus.Decided
: ProposalStatus.ToBeDecided;
}

return proposal;
}

[View]
public Kernel.Authorization GetAuthorization(Address address)
{
// case 1: get authorization of normal multi sig account
if (!address.Equals(Genesis))
{
Api.Assert(_multiSig.TryGet(address, out var authorization), "MultiSigAccount not found.");
return authorization;
}

// case 2: get authorization of system account
var reviewers = Api.GetMiners().PublicKeys;
var auth = new Kernel.Authorization
{
MultiSigAccount = Genesis,
ExecutionThreshold = SystemThreshold((uint) reviewers.Count),
ProposerThreshold = 0
};
auth.Reviewers.AddRange(reviewers.Select(r => new Reviewer
{
PubKey = ByteString.CopyFrom(ByteArrayHelpers.FromHexString(r)),
Weight = 1 // BP weight
}));

return auth;
}

#endregion view

#region Actions
Expand All @@ -121,14 +148,21 @@ public byte[] CreateMultiSigAccount(Kernel.Authorization authorization)
{
Api.Assert(authorization.Reviewers.Count > 0 && authorization.Reviewers.All(r => r.PubKey.Length > 0),
"Invalid authorization for multi signature.");
// TODO: check public key -- if no Multisig account then ELF_chainID_SHA^2(authorization)
Address multiSigAccount = authorization.MultiSigAccount ??
Address.FromPublicKey(authorization.ToByteArray().ToArray());
Api.Assert(_multiSig.GetValue(multiSigAccount).Equals(new Kernel.Authorization()),
"MultiSigAccount already existed.");
Api.Assert(!_multiSig.TryGet(multiSigAccount, out _),"MultiSigAccount already existed.");
uint accumulatedWeights =
authorization.Reviewers.Aggregate<Reviewer, uint>(0, (weights, r) => weights + r.Weight);

// Weight accumulation should be more than authorization execution threshold.
Api.Assert(accumulatedWeights >= authorization.ExecutionThreshold, "Invalid authorization.");

// At least one reviewer can propose.
bool canBeProposed = authorization.Reviewers.Any(r => r.Weight >= authorization.ProposerThreshold);
Api.Assert(canBeProposed, "Invalid authorization.");

authorization.MultiSigAccount = multiSigAccount;
_multiSig.SetValue(multiSigAccount, authorization);

return multiSigAccount.DumpByteArray();
}

Expand All @@ -146,13 +180,11 @@ public byte[] Propose(Proposal proposal)
Api.Assert(Api.CurrentBlockTime < timestamp, "Expired proposal.");

Hash hash = proposal.GetHash();
Api.Assert(_proposals.GetValue(hash).Equals(new Proposal()), "Proposal already created.");
Api.Assert(!_proposals.TryGet(hash, out _), "Proposal already created.");

// check authorization of proposer public key
var auth = GetAuth(proposal.MultiSigAccount);
Api.Assert(!auth.Equals(new Kernel.Authorization()), "MultiSigAccount not found.");
var auth = GetAuthorization(proposal.MultiSigAccount);
CheckAuthority(proposal, auth);

_proposals.SetValue(hash, proposal);
return hash.DumpByteArray();
}
Expand All @@ -163,26 +195,22 @@ public bool SayYes(Approval approval)
Hash hash = approval.ProposalHash;

// check approval not existed
var approved = _approved.GetValue(hash);
Api.Assert(approved.Equals(new Approved()) || !approved.Approvals.Contains(approval),
Api.Assert(!_approved.TryGet(hash, out var approved) || !approved.Approvals.Contains(approval),
"Approval already existed.");

// check authorization and permission
var proposal = _proposals.GetValue(hash);
Api.Assert(!proposal.Equals(new Proposal()), "Proposal not found.");
Api.Assert(_proposals.TryGet(hash, out var proposal), "Proposal not found.");
Api.Assert(Api.CurrentBlockTime < TimerHelper.ConvertFromUnixTimestamp(proposal.ExpiredTime), "Expired proposal.");

var msig = proposal.MultiSigAccount;
var authorization = GetAuth(msig);

Api.Assert(!authorization.Equals(new Kernel.Authorization()), "Authorization not found."); // should never happen

var authorization = GetAuthorization(msig);
byte[] toSig = proposal.TxnData.ToByteArray().CalculateHash();
byte[] pubKey = Api.RecoverPublicKey(approval.Signature.ToByteArray(), toSig);
Api.Assert(Api.RecoverPublicKey().SequenceEqual(pubKey), "Invalid approval.");
Api.Assert(authorization.Reviewers.Any(r => r.PubKey.ToByteArray().SequenceEqual(pubKey)), "Not authorized approval.");

CheckSignature(proposal.TxnData.ToByteArray(), approval.Signature.ToByteArray());
approved = approved ?? new Approved();
approved.Approvals.Add(approval);
_approved.SetValue(hash, approved);

Expand All @@ -197,19 +225,17 @@ public bool SayYes(Approval approval)

public byte[] Release(Hash proposalHash)
{
var proposal = _proposals.GetValue(proposalHash);
Api.Assert(!proposal.Equals(new Proposal()), "Proposal not found");
Api.Assert(_proposals.TryGet(proposalHash, out var proposal), "Proposal not found.");
// check expired time of proposal
Api.Assert(Api.CurrentBlockTime < TimerHelper.ConvertFromUnixTimestamp(proposal.ExpiredTime), "Expired proposal.");
Api.Assert(Api.CurrentBlockTime < TimerHelper.ConvertFromUnixTimestamp(proposal.ExpiredTime),
"Expired proposal.");
Api.Assert(proposal.Status != ProposalStatus.Released, "Proposal already released");

var msigAccount = proposal.MultiSigAccount;
var auth = GetAuth(msigAccount);
Api.Assert(!auth.Equals(new Kernel.Authorization())); // this should not happen.
var auth = GetAuthorization(msigAccount);

// check approvals
var approved = _approved.GetValue(proposalHash);

Api.Assert(CheckApproval(approved, auth, proposal), "Not authorized to release.");

// check and append signatures to packed txn
Expand All @@ -223,32 +249,11 @@ public byte[] Release(Hash proposalHash)
}

#endregion

public Kernel.Authorization GetAuth(Address address)
{
// case 1: get authorization of normal multi sig account
if (!address.Equals(Genesis))
return _multiSig.GetValue(address);
// case 2: get authorization of system account
var reviewers = Api.GetMiners().PublicKeys;
var auth = new Kernel.Authorization
{
MultiSigAccount = Genesis,
ExecutionThreshold = SystemThreshold((uint) reviewers.Count),
ProposerThreshold = 0
};
auth.Reviewers.AddRange(reviewers.Select(r => new Reviewer
{
PubKey = ByteString.CopyFrom(ByteArrayHelpers.FromHexString(r)),
Weight = 1 // BP weight
}));

return auth;
}


public bool IsMultiSigAccount(Address address)
{
if (address.Equals(Genesis) || _multiSig.GetValue(address) != null)
if (address.Equals(Genesis) || _multiSig.TryGet(address, out _))
{
return true;
}
Expand Down Expand Up @@ -290,7 +295,7 @@ private void CheckAuthority(Proposal proposal, Kernel.Authorization authorizatio
var proposerPerm = reviewer?.Weight ?? 0;
Api.Assert(
Api.GetFromAddress().Equals(proposal.Proposer) &&
proposerPerm >= authorization.ProposerThreshold, "Not authorized to propose.");
proposerPerm >= authorization.ProposerThreshold, "Unable to propose.");
}
// No need to check authority if threshold is 0.
// check packed transaction
Expand Down
2 changes: 1 addition & 1 deletion AElf.Contracts.Genesis.Tests/ContractZeroTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void Test()
Assert.Equal(address, _contractShim.TransactionContext.Trace.RetVal.Data.DeserializeToPbMessage<Address>());

// chang owner and query again, owner will be new owner
var newOwner = Address.Generate();
var newOwner = Address.Genesis;
_contractShim.ChangeContractOwner(address, newOwner);
_contractShim.GetContractOwner(address);
var queryNewOwner = _contractShim.TransactionContext.Trace.RetVal.Data.DeserializeToPbMessage<Address>();
Expand Down
4 changes: 3 additions & 1 deletion AElf.Contracts.Genesis.Tests/TestContractShim.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using AElf.Kernel;
using Google.Protobuf;
using AElf.SmartContract;
Expand Down Expand Up @@ -67,7 +68,8 @@ public byte[] UpdateSmartContract(Address address, byte[] code)

TransactionContext = new TransactionContext
{
Transaction = tx
Transaction = tx,
CurrentBlockTime = DateTime.UtcNow
};
Executive.SetTransactionContext(TransactionContext).Apply().Wait();
TransactionContext.Trace.SmartCommitChangesAsync(_mock.StateManager).Wait();
Expand Down
6 changes: 4 additions & 2 deletions AElf.Sdk.CSharp/Api.cs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,8 @@ public static void CheckAuthority(Address fromAddress = null)
if (_transactionContext.Transaction.Sigs.Count == 1)
// No need to verify signature again if it is not multi sig account.
return;
Call(AuthorizationContractAddress, "GetAuth", _transactionContext.Transaction.From);
Assert(Call(AuthorizationContractAddress, "GetAuthorization", _transactionContext.Transaction.From),
"Unable to get authorization.");
var auth = GetCallResult().DeserializeToPbMessage<Authorization>();

// Get tx hash
Expand Down Expand Up @@ -493,7 +494,8 @@ public static Hash Propose(string proposalName, double waitingPeriod, Address fr
To = targetAddress,
MethodName = invokingMethod,
Params = ByteString.CopyFrom(ParamsPacker.Pack(args)),
Type = TransactionType.MsigTransaction
Type = TransactionType.MsigTransaction,
Time = Timestamp.FromDateTime(CurrentBlockTime)
}.ToByteArray();
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSpan diff = CurrentBlockTime.AddSeconds(waitingPeriod).ToUniversalTime() - origin;
Expand Down

0 comments on commit 0f4a0a6

Please sign in to comment.