Skip to content

Commit

Permalink
Merge branch 'develop' into 'master'
Browse files Browse the repository at this point in the history
Develop

See merge request company-projects/Meadow!47
  • Loading branch information
Xenomega committed Oct 8, 2018
2 parents 0b943de + 68469ff commit 5e400b7
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 11 deletions.
18 changes: 18 additions & 0 deletions src/Meadow.CoverageReport/AstNode.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Meadow.CoverageReport.AstTypes;
using Meadow.CoverageReport.AstTypes.Enums;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
Expand Down Expand Up @@ -140,6 +141,23 @@ public static AstNodeType GetTypeFromString(string nodeTypeString)
}
}

public static AstDeclarationVisibility GetVisibilityFromString(string visibilityTypeString)
{
switch (visibilityTypeString)
{
case "private":
return AstDeclarationVisibility.Private;
case "public":
return AstDeclarationVisibility.Public;
case "external":
return AstDeclarationVisibility.External;
case "internal":
return AstDeclarationVisibility.Internal;
default:
return AstDeclarationVisibility.Public;
}
}

public static AstNode GetParent(AstNode node)
{
var parent = node.Node.Parent;
Expand Down
8 changes: 7 additions & 1 deletion src/Meadow.CoverageReport/AstTypes/AstFunctionDefinition.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Newtonsoft.Json.Linq;
using Meadow.CoverageReport.AstTypes.Enums;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -14,6 +15,10 @@ public class AstFunctionDefinition : AstNode
/// </summary>
public string Name { get; }
/// <summary>
/// The visibility of this function.
/// </summary>
public AstDeclarationVisibility Visibility { get; }
/// <summary>
/// Indicates whether the function is a constructor for its parent <see cref="AstContractDefinition"/> or not.
/// </summary>
public bool IsConstructor { get; }
Expand All @@ -32,6 +37,7 @@ public AstFunctionDefinition(JObject node) : base(node)
{
// Set our properties
Name = node.SelectToken("name")?.Value<string>();
Visibility = GetVisibilityFromString(node.SelectToken("visibility")?.Value<string>());
IsConstructor = node.SelectToken("isConstructor")?.Value<bool?>() == true;
Parameters = node.SelectTokens("parameters.parameters[*]").Select(x => Create<AstVariableDeclaration>((JObject)x)).ToArray();
ReturnParameters = node.SelectTokens("returnParameters.parameters[*]").Select(x => Create<AstVariableDeclaration>((JObject)x)).ToArray();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Meadow.CoverageReport.AstTypes.Enums
{
public enum AstDeclarationVisibility
{
Public,
Private,
Internal,
External,
}
}
11 changes: 11 additions & 0 deletions src/Meadow.CoverageReport/Debugging/ExecutionTraceAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ private void FillUnchangedValues()
Core.EthTypes.Data[] lastKnownStack = null;
Core.EthTypes.Data[] lastKnownMemory = null;
Address? lastKnownContractAddress = null;
byte[] lastKnownCallData = null;
byte[] lastKnownCode = null;
string lastKnownCodeHex = null;
Dictionary<Memory<byte>, byte[]> lastKnownStorage = null;
Expand Down Expand Up @@ -189,6 +190,16 @@ private void FillUnchangedValues()
lastKnownContractAddress = (Address)tracePoint.ContractAddress;
}

// Update any "unchanged" (null) references to the last known reference for call data
if (tracePoint.CallData == null)
{
tracePoint.CallData = lastKnownCallData;
}
else
{
lastKnownCallData = tracePoint.CallData;
}

// Update any "unchanged" (null) references to the last known reference for code
if (tracePoint.Code == null)
{
Expand Down
7 changes: 4 additions & 3 deletions src/Meadow.CoverageReport/SourceAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ static class SourceAnalysis
AstNodeType.VariableDeclaration,
//AstNodeType.Literal,
AstNodeType.PlaceholderStatement,
AstNodeType.UserDefinedTypeName
AstNodeType.UserDefinedTypeName,
AstNodeType.InlineAssembly
};

/// <summary>
Expand All @@ -70,11 +71,11 @@ static class SourceAnalysis
AstNodeType.ForStatement,
AstNodeType.FunctionCall,
AstNodeType.IndexAccess,
AstNodeType.InlineAssembly,
//AstNodeType.InlineAssembly,
AstNodeType.MemberAccess,
AstNodeType.Return,
AstNodeType.UnaryOperation,
// AstNodeType.VariableDeclarationStatement
//AstNodeType.VariableDeclarationStatement
};

public static AnalysisResults Run(
Expand Down
18 changes: 16 additions & 2 deletions src/Meadow.DebugExampleTests/Contracts/VarAnalysisContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,24 @@ contract VarAnalysisContract
nestedMapping[key1][key2] = enumValue;
}

function testExternalCallDataArgs(address[] testArr, uint256 u1, uint256 u2) external {
function throwExternalCallDataArgs(address[] testArr, uint256 u1, uint256 u2) external {
// Arguments in this context (external) should be resolved from calldata, not memory)
for(uint i=0; i< testArr.length; i+=1) {
require(testArr[i] != address(0));
assert(false);
}
}

function throwExternalCallDataArgs2(address[] testArr1, address[] testArr2, uint256 u1, uint256 u2) external {
// Arguments in this context (external) should be resolved from calldata, not memory)
for(uint i=0; i< testArr1.length; i+=1) {
assert(false);
}
}

function throwExternalCallDataArgs3(uint256 u1, address[] testArr1, address[] testArr2, uint256 u2) external {
// Arguments in this context (external) should be resolved from calldata, not memory)
for(uint i=0; i< testArr1.length; i+=1) {
assert(false);
}
}
}
10 changes: 8 additions & 2 deletions src/Meadow.DebugExampleTests/DebuggerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,14 @@ public async Task TestMappings()
[TestMethod]
public async Task TestExternalCallDataArgs()
{
Address[] addresses = new Address[] { Accounts[0] };
await _contract.testExternalCallDataArgs(addresses, 10, 10);
Address[] addresses1 = new Address[] { new Address("0x7777777777777777777777777777777777777777"), new Address("0x8888888888888888888888888888888888888888"), new Address("0x9999999999999999999999999999999999999999") };
Address[] addresses2 = new Address[] { new Address("0x6666666666666666666666666666666666666666") };
await _contract.throwExternalCallDataArgs(addresses1, 10, 11).ExpectRevertTransaction();
await _contract.throwExternalCallDataArgs2(addresses1, addresses2, 10, 11).ExpectRevertTransaction();
await _contract.throwExternalCallDataArgs3(10, addresses1, addresses2, 11).ExpectRevertTransaction();

// TODO: Verify variables.
Assert.Inconclusive();
}
}
}
23 changes: 20 additions & 3 deletions src/Meadow.EVM/Debugging/Tracing/ExecutionTrace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ public class ExecutionTrace
/// Indicates if the last tracepoint had changed storage, so it is known to be included for the current step.
/// </summary>
private bool _lastStorageChanged;
/// <summary>
/// The last call depth we had recorded.
/// </summary>
private int _lastCallDepth;
#endregion

#region Properties
Expand All @@ -46,6 +50,7 @@ public ExecutionTrace()
Exceptions = new List<ExecutionTraceException>();
_lastContractAddress = null;
_lastMemoryChangeCount = 0;
_lastCallDepth = -1;
_lastStorageChanged = false;
}
#endregion
Expand All @@ -57,20 +62,31 @@ public void RecordExecution(MeadowEVM evm, InstructionBase instruction, BigInteg
Address deployedAddress = evm.Message.GetDeployedCodeAddress();
bool isDeployed = deployedAddress == evm.Message.CodeAddress;

// Declare our memory + last returned data, null initially (indicating it is unchanged from the last known value).
// Declare our memory null initially (indicating it is unchanged from the last known value).
byte[] memory = null;

// Determine if our context has changed between contracts, or our memory has changed.
bool contextChanged = _lastContractAddress != deployedAddress;
bool memoryChanged = _lastMemoryChangeCount != evm.ExecutionState.Memory.ChangeCount;
bool callDepthChanged = _lastCallDepth != evm.Message.Depth;

// If our context or memory has changed, we'll want to include the memory. (This way our simple lookup for memory will consist of checking in the current trace point, or if null, loop backwards to the last one you find).
if (contextChanged || memoryChanged)
if (contextChanged || callDepthChanged || memoryChanged)
{
memory = evm.ExecutionState.Memory.ToArray();
}

// Update our last processed contract address and change count
// Declare our call data
byte[] callData = null;

// If our call data changed, we'll want to include it.
if (contextChanged || callDepthChanged)
{
callData = evm.Message.Data;
}

// Update our last processed contract address, change count, and scope depth
_lastCallDepth = (int)evm.Message.Depth;
_lastContractAddress = deployedAddress;
_lastMemoryChangeCount = evm.ExecutionState.Memory.ChangeCount;

Expand Down Expand Up @@ -113,6 +129,7 @@ public void RecordExecution(MeadowEVM evm, InstructionBase instruction, BigInteg
// Add a new tracepoint.
var tracePoint = new ExecutionTracePoint()
{
CallData = callData,
Code = codeSegment,
ContractAddress = contextChanged ? deployedAddress : null,
ContractDeployed = isDeployed,
Expand Down
5 changes: 5 additions & 0 deletions src/Meadow.EVM/Debugging/Tracing/ExecutionTracePoint.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Meadow.EVM.Data_Types.Addressing;
using Meadow.EVM.EVM.Instructions;
using Meadow.EVM.EVM.Messages;
using System;
using System.Collections.Generic;
using System.Numerics;
Expand All @@ -11,6 +12,10 @@ public class ExecutionTracePoint
{
#region Properties
/// <summary>
/// The <see cref="EVMMessage.Data"/> at the time of execution.
/// </summary>
public byte[] CallData { get; set; }
/// <summary>
/// The entire code segment being processed at this point. NULL if unchanged since last known value.
/// </summary>
public byte[] Code { get; set; }
Expand Down
6 changes: 6 additions & 0 deletions src/Meadow.JsonRpc/Types/Debugging/ExecutionTracePoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ public class ExecutionTracePoint
{
#region Properties
/// <summary>
/// The call data set at this trace point.
/// If NULL, then derived from last known value in the trace.
/// </summary>
[JsonProperty("callData"), JsonConverter(typeof(JsonRpcHexConverter))]
public byte[] CallData { get; set; }
/// <summary>
/// The full code segment executed at this trace point (including constructor args if deploying, etc).
/// Hence, this section will treat code segments as the EVM internally does, not discerning higher level structures and splitting them.
/// If NULL, then derived from last known value in the trace.
Expand Down
1 change: 1 addition & 0 deletions src/Meadow.TestNode/JsonTypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ internal static ExecutionTrace CoreExecutionTraceJsonExecutionTrace(Meadow.EVM.D
// Obtain our memory
tracepoints[i] = new ExecutionTracePoint()
{
CallData = executionTracePoint.CallData,
Code = executionTracePoint.Code,
ContractAddress = executionTracePoint.ContractAddress == null ? (Address?)null : new Address(executionTracePoint.ContractAddress.ToByteArray()),
ContractDeployed = executionTracePoint.ContractDeployed,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,11 @@ contract VarAnalysisContract
{
nestedMapping[key1][key2] = enumValue;
}

function throwExternalCallDataArgs(address[] testArr, uint256 u1, uint256 u2) external {
// Arguments in this context (external) should be resolved from calldata, not memory)
for(uint i=0; i< testArr.length; i+=1) {
assert(false);
}
}
}
18 changes: 18 additions & 0 deletions src/Meadow.UnitTestTemplate.Test/DebuggerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,5 +194,23 @@ public async Task TestMappings()
// TODO: Verify variables.
Assert.Inconclusive();
}

[TestMethod]
public async Task TestExternalCallDataArgs()
{
Address[] addresses = new Address[] { new Address("0x7777777777777777777777777777777777777777"), new Address("0x8888888888888888888888888888888888888888"), new Address("0x9999999999999999999999999999999999999999") };
await _contract.throwExternalCallDataArgs(addresses, 10, 10).ExpectRevertTransaction();

// Obtain an execution trace and parse locals from the last point in it (where the exception occurred).
var executionTrace = await RpcClient.GetExecutionTrace();
ExecutionTraceAnalysis traceAnalysis = new ExecutionTraceAnalysis(executionTrace);

// Obtain our local/state variables.
var localVariables = traceAnalysis.GetLocalVariables(RpcClient);
var stateVariables = traceAnalysis.GetStateVariables(RpcClient);

// TODO: Verify variables.
Assert.Inconclusive();
}
}
}

0 comments on commit 5e400b7

Please sign in to comment.