sbuilder-ethereum 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/VERSION +1 -0
  3. data/lib/mixer/decl_ref.rb +19 -0
  4. data/lib/mixer/domain_ref.rb +18 -0
  5. data/lib/mixer/scope.rb +92 -0
  6. data/lib/mixer/scoped.rb +17 -0
  7. data/lib/mixer/symbol_ref.rb +16 -0
  8. data/lib/mixer/type_symbol.rb +75 -0
  9. data/lib/plugin/plugin.rb +332 -0
  10. data/lib/resources/correctness/accouns_type.tla +1 -0
  11. data/lib/resources/correctness/accounts_unique.tla +2 -0
  12. data/lib/resources/correctness/accounts_valid.tla +2 -0
  13. data/lib/resources/correctness/storage_root_unique.tla +2 -0
  14. data/lib/resources/correctness/total_value.tla +1 -0
  15. data/lib/resources/eth/accounts_state.tla +2 -0
  16. data/lib/resources/eth/accounts_temp.tla +2 -0
  17. data/lib/resources/eth/address_free.tla +2 -0
  18. data/lib/resources/eth/mined_state.tla +1 -0
  19. data/lib/resources/eth/storageRoot.tla +1 -0
  20. data/lib/resources/eth/storageRoot_temp.tla +1 -0
  21. data/lib/resources/mine/mine_entry.tla +4 -0
  22. data/lib/resources/mine/mine_service.tla +22 -0
  23. data/lib/resources/operators/elementExists.tla +4 -0
  24. data/lib/resources/operators/gasPrice.tla +2 -0
  25. data/lib/resources/operators/gasValue.tla +2 -0
  26. data/lib/resources/operators/getElement.tla +5 -0
  27. data/lib/resources/operators/intrinsicGas.tla +4 -0
  28. data/lib/resources/operators/transactionGas.tla +4 -0
  29. data/lib/resources/operators/upFrontCost.tla +6 -0
  30. data/lib/resources/personal_newAccount/personal_newAccount_done.tla +14 -0
  31. data/lib/resources/personal_newAccount/personal_newAccount_entry.tla +10 -0
  32. data/lib/resources/personal_newAccount/personal_newAccount_service.tla +29 -0
  33. data/lib/resources/removed/sendTransaction_entry.tla +5 -0
  34. data/lib/resources/removed/sendTransaction_service.tla +36 -0
  35. data/lib/resources/removed/tst.tla +1 -0
  36. data/lib/resources/transaction/ethereum_service_done.tla +24 -0
  37. data/lib/resources/transaction/ethereum_service_pop.tla +24 -0
  38. data/lib/resources/transaction/ethereum_service_push.tla +14 -0
  39. data/lib/resources/transaction/ethereum_service_start.tla +13 -0
  40. data/lib/resources/transaction/status_fail.tla +1 -0
  41. data/lib/resources/transaction/status_ok.tla +1 -0
  42. data/lib/sbuilder-ethereum.rb +52 -0
  43. data/lib/sbuilder/compile.rb +163 -0
  44. data/lib/sbuilder/constants.rb +93 -0
  45. data/lib/sbuilder/exception.rb +22 -0
  46. data/lib/sbuilder/generate/sexp_processor_tla.rb +2674 -0
  47. data/lib/sbuilder/generate/tla_element_generator.rb +1206 -0
  48. data/lib/sbuilder/generate/tla_element_text.rb +703 -0
  49. data/lib/sbuilder/load.rb +119 -0
  50. data/lib/sbuilder/mustache/renderer.rb +152 -0
  51. data/lib/sbuilder/render.rb +141 -0
  52. data/lib/sbuilder/s.rb +21 -0
  53. data/lib/sbuilder/sexp_ast.rb +1378 -0
  54. data/lib/sbuilder/sexp_processor_api.rb +184 -0
  55. data/lib/sbuilder/sexp_processor_canonize.rb +326 -0
  56. data/lib/sbuilder/sexp_processor_dataflow.rb +461 -0
  57. data/lib/sbuilder/sexp_processor_ethereum.rb +127 -0
  58. data/lib/sbuilder/sexp_processor_need_to_canonize.rb +572 -0
  59. data/lib/sbuilder/sexp_processor_snippet.rb +154 -0
  60. data/lib/sbuilder/sexp_processor_symboltable1.rb +296 -0
  61. data/lib/sbuilder/sexp_processor_symboltable2.rb +175 -0
  62. data/lib/sbuilder/sexp_utils.rb +417 -0
  63. data/lib/utils/logger.rb +82 -0
  64. data/lib/utils/string_inject.rb +11 -0
  65. data/sbuilder-ethereum.gemspec +39 -0
  66. metadata +190 -0
@@ -0,0 +1 @@
1
+ accounts_type == \A e \in {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}}: e \in {{#SPEC_NAME}}definitions.Accounts{{/SPEC_NAME}}
@@ -0,0 +1,2 @@
1
+ \* Invariant: unique entries in account state variable
2
+ accounts_unique == uniqueElements( {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}}, "address" )
@@ -0,0 +1,2 @@
1
+ \* valid account must have value >= 0, and address # Nil
2
+ accounts_valid == \A a \in {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}}: a.address # Nil /\ a.balance >= 0
@@ -0,0 +1,2 @@
1
+ \* Invariant: unique entries in storageRoot state variable
2
+ storageRoot_unique == uniqueElements( {{#SPEC_NAME}}eth.storageRoot{{/SPEC_NAME}}, "address" )
@@ -0,0 +1 @@
1
+ total_value == Stable => ( {{#SPEC_NAME}}eth.mined{{/SPEC_NAME}} + SumRecordField( {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}}, "balance" ) = 0 )
@@ -0,0 +1,2 @@
1
+ \* account entries
2
+ {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}} = {};
@@ -0,0 +1,2 @@
1
+ \* account transient state
2
+ {{#SPEC_NAME}}eth.accounts_temp{{/SPEC_NAME}} = <<>>;
@@ -0,0 +1,2 @@
1
+ \* Unassigned addresses
2
+ {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}} = {{#SPEC_NAME}}domains.eth_address{{/SPEC_NAME}} \ { Nil };
@@ -0,0 +1 @@
1
+ {{#SPEC_NAME}}eth.mined{{/SPEC_NAME}} = 0;
@@ -0,0 +1 @@
1
+ {{#SPEC_NAME}}eth.storageRoot{{/SPEC_NAME}} = {};
@@ -0,0 +1 @@
1
+ {{#SPEC_NAME}}eth.storageRoot_temp{{/SPEC_NAME}} = <<>>;
@@ -0,0 +1,4 @@
1
+ macro {{#SPEC_NAME}}service_implementation.geth_mine(){{/SPEC_NAME}}( input ) {
2
+
3
+ call {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}( input );
4
+ }
@@ -0,0 +1,22 @@
1
+ procedure {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}( input ) {
2
+
3
+ {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}_enter:
4
+
5
+ \* Check that account input.etherbase exists
6
+ if ( { e \in {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}}: e.address = input.beneficiary } = {}) {
7
+ goto {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}_exit;
8
+ };
9
+
10
+ {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}_ok:
11
+
12
+ \* Update on 'account.balance' with 'input.value'
13
+ {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}} :=
14
+ { IF e.address = input.beneficiary THEN [ e EXCEPT !.balance = e.balance + input.value ] ELSE e : e \in {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}} };
15
+
16
+ \* Update total value 'mined'
17
+ {{#SPEC_NAME}}eth.mined{{/SPEC_NAME}} := {{#SPEC_NAME}}eth.mined{{/SPEC_NAME}} - input.value;
18
+
19
+ {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}_exit:
20
+ return;
21
+
22
+ }
@@ -0,0 +1,4 @@
1
+ (*
2
+ * Unique element exists
3
+ *)
4
+ elementExists( set, key, id ) == Cardinality( { e \in set : e[key] = id } ) = 1
@@ -0,0 +1,2 @@
1
+ \* Use integer math, and gasPrice is just 1
2
+ gasPrice == 0
@@ -0,0 +1,2 @@
1
+ \* @return [Integer] gas * gasPrice
2
+ gasValue( gas ) == gas * gasPrice
@@ -0,0 +1,5 @@
1
+ (*
2
+ * Return element from 'set' such that element['key'] == 'id'
3
+ * Assume 'id' unique, and element exists
4
+ *)
5
+ getElement( set, key, id ) == ( CHOOSE x \in { e \in set : e[key] = id } : TRUE )
@@ -0,0 +1,4 @@
1
+ (* Always consume at least one unit of gas
2
+ * Account must have balance >= intrinsicGas*gasPrice before execution
3
+ *)
4
+ intrinsicGas == 1
@@ -0,0 +1,4 @@
1
+ (*
2
+ * Running transaction consumes always 1 unit of gas.
3
+ *)
4
+ transactionGas == 1
@@ -0,0 +1,6 @@
1
+ (*
2
+ * Value account must hold before transaction possible to start
3
+ *
4
+ * @return [Integer] request.value + gasPrice * intrinsicGas
5
+ *)
6
+ upFrontCost( request ) == request.value + gasPrice * intrinsicGas
@@ -0,0 +1,14 @@
1
+ macro personal_newAccount_done( interface ) {
2
+
3
+ \* like ethereum_service_done( interface ) + creates eth_storageRoot
4
+
5
+
6
+ eth_storageRoot := Head(eth_storageRoot_temp) \union { [address |-> InfrastructureServiceGetResponse( "personal_newAccount()" ) ] };
7
+ eth_accounts := Head(eth_accounts_temp);
8
+ \* eth_gasUsed := Head(eth_gasUsed_temp);
9
+
10
+ eth_storageRoot_temp := <<>>;
11
+ eth_accounts_temp := <<>>;
12
+ \* eth_gasUsed_temp := <<>>;
13
+
14
+ }
@@ -0,0 +1,10 @@
1
+ macro {{#SPEC_NAME}}service_implementation.personal_newAccount(){{/SPEC_NAME}}( input ) {
2
+
3
+ \* prepare for transaction
4
+ \* print <<"TRACE>","TX-start@personal_newAccount(): push block state to stack">>;
5
+
6
+ ethereum_service_start();
7
+
8
+ call {{#SPEC_NAME}}eth.personal_newAccount{{/SPEC_NAME}}( [ codeHash |-> input.dummy, address |-> Nil ] );
9
+
10
+ }
@@ -0,0 +1,29 @@
1
+
2
+ (*
3
+ * @param [codeHash] class name, Nil for non-contract accounts
4
+ * @param [address] Nil|address to take from pools
5
+ *)
6
+ procedure {{#SPEC_NAME}}eth.personal_newAccount{{/SPEC_NAME}}( input ) {
7
+
8
+ {{#SPEC_NAME}}eth.personal_newAccount{{/SPEC_NAME}}_enter:
9
+
10
+ \* Must have NextId available in free address pool
11
+ assert( {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}} # {} );
12
+
13
+ \* Create account record in 'accounts' variable, input.dummy is default - because no input defined
14
+ {{#SPEC_NAME}}eth.accounts_temp{{/SPEC_NAME}} :=
15
+ UpdateTop( {{#SPEC_NAME}}eth.accounts_temp{{/SPEC_NAME}},
16
+ Head( {{#SPEC_NAME}}eth.accounts_temp{{/SPEC_NAME}} ) \union { [ address |-> NextId( {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}}, input.address ), balance |-> 0, codeHash |-> input.codeHash ]});
17
+
18
+ \* Set return
19
+ InfrastructureServiceReturn( "personal_newAccount()", status_OK, NextId( {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}}, input.address ) );
20
+
21
+ \* Remove 'NextId' from frees address pool
22
+ {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}} :=
23
+ {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}} \ { NextId( {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}}, input.address ) };
24
+
25
+ {{#SPEC_NAME}}eth.personal_newAccount{{/SPEC_NAME}}_exit:
26
+
27
+ return;
28
+
29
+ }
@@ -0,0 +1,5 @@
1
+ macro {{#SPEC_NAME}}service_implementation.sendTransaction(){{/SPEC_NAME}}( input ) {
2
+
3
+ call sendTransaction( input );
4
+
5
+ }
@@ -0,0 +1,36 @@
1
+ procedure sendTransaction( input ) {
2
+
3
+ sendTransaction_enter:
4
+
5
+
6
+ (* Validate send transaction
7
+ - must be transferring accross different addresses 'to' <> 'from'
8
+ - sender 'from' must have enough 'value'
9
+ *)
10
+
11
+ if (
12
+ { e \in accounts : e.aid = input.from } = {}
13
+ \/ input.from = input.to
14
+ \/ (CHOOSE x \in { e \in accounts: e.aid = input.from } : TRUE ).value < input.value
15
+ ) {
16
+
17
+ goto sendTransaction_exit;
18
+
19
+ };
20
+
21
+ sendTransaction_transaction_ok:
22
+
23
+
24
+ \* Send: 'to.value' += input.value; 'from.value' -= input.value
25
+
26
+ accounts := { e \in accounts : e.aid # input.from /\ e.aid # input.to }
27
+ \union
28
+ { [ e_to_new EXCEPT !.value = e_to_new.value + input.value ] : e_to_new \in { e_to \in accounts: e_to.aid = input.to } }
29
+ \union
30
+ { [ e_from_new EXCEPT !.value = e_from_new.value - input.value ] : e_from_new \in { e_from \in accounts: e_from.aid = input.from } }
31
+ ;
32
+
33
+ sendTransaction_exit:
34
+ return;
35
+
36
+ }
@@ -0,0 +1 @@
1
+ tst == TRUE
@@ -0,0 +1,24 @@
1
+ (*
2
+ * Interface process (called scheduled) has finished.
3
+ * Check service response status, and
4
+ * commit changes in 'eth_storageRoot' and 'eth_accounts', if success.
5
+ * In any case clear variables modeling block status because
6
+ * they are not needed anymore (after all scheduler starts a new
7
+ * round).
8
+ *
9
+ *)
10
+ macro ethereum_service_done( interface ) {
11
+
12
+ if ( InfrastructureServiceGetStatus(interface ) = TRUE ) {
13
+ \* Success commit changes to 'temp' & cleanup
14
+ {|^preferences.tla-trace|}\* {|/preferences.tla-trace|} print <<"TRACE>", "TX-end@", interface, "success: restore eth_storageRoot ">>;
15
+ {|^preferences.tla-trace|}\* {|/preferences.tla-trace|} print <<"TRACE>", "TX-end@", interface, "success: restore eth_accounts ">>;
16
+ (* {|^preferences.tla-trace|}\* {|/preferences.tla-trace|} print <<"TRACE>", "TX-end@", interface, "success: restore eth_gasUsed ">>; *)
17
+ eth_storageRoot := Head(eth_storageRoot_temp);
18
+ eth_accounts := Head(eth_accounts_temp);
19
+ \* eth_gasUsed := Head(eth_gasUsed_temp);
20
+ };
21
+ eth_storageRoot_temp := <<>>;
22
+ eth_accounts_temp := <<>>;
23
+ \* eth_gasUsed_temp := <<>>;
24
+ }
@@ -0,0 +1,24 @@
1
+ (*
2
+ * Service procedure for 'interface' has finished.
3
+ * Check status of service response.
4
+ * For success make changes in procedure permanent by propagating
5
+ * stack top to top-1..bottom.
6
+ *
7
+ * In any case pop one element from stack.
8
+ *
9
+ *)
10
+
11
+ macro ethereum_service_pop( interface ) {
12
+
13
+ if ( InfrastructureServiceGetStatus(interface ) = TRUE ) {
14
+ \* Success - propage changes, and make the permanent
15
+ eth_storageRoot_temp := PropageTopAndPop( eth_storageRoot_temp );
16
+ eth_accounts_temp := PropageTopAndPop( eth_accounts_temp );
17
+ \* eth_gasUsed_temp := PropageTopAndPop( eth_gasUsed_temp );
18
+ }
19
+ else {
20
+ eth_storageRoot_temp := Tail(eth_storageRoot_temp);
21
+ eth_accounts_temp := Tail(eth_accounts_temp);
22
+ \* eth_gasUsed_temp := Tail( eth_gasUsed_temp );
23
+ };
24
+ }
@@ -0,0 +1,14 @@
1
+ (*
2
+ * Macro called when service starts. Duplicates current
3
+ * top of stack.
4
+ *
5
+ * @see ethereum_service_start
6
+ * @see ethereum_service_done
7
+ *)
8
+ macro {{#SPEC_NAME}}framework-svc.ethereum_service_push{{/SPEC_NAME}}() {
9
+
10
+ eth_storageRoot_temp := Push( eth_storageRoot_temp, Head( eth_storageRoot_temp )) ;
11
+ eth_accounts_temp := Push( eth_accounts_temp, Head( eth_accounts_temp ));
12
+ \* eth_gasUsed_temp := Push( eth_gasUsed_temp, Head(eth_gasUsed_temp));
13
+
14
+ }
@@ -0,0 +1,13 @@
1
+ (*
2
+ * Macro called when transaction starts.
3
+ * Inializes ethreum block context to stack.
4
+ *
5
+ * @see ethereum_service_done
6
+ * @see ethereum_service_push
7
+ *)
8
+ macro {{#SPEC_NAME}}framework-svc.ethereum_service_start{{/SPEC_NAME}}() {
9
+
10
+ eth_storageRoot_temp := <<eth_storageRoot>>;
11
+ eth_accounts_temp := <<eth_accounts>>;
12
+ \* eth_gasUsed_temp := <<eth_gasUsed>>;
13
+ }
@@ -0,0 +1 @@
1
+ status_FAIL == FALSE
@@ -0,0 +1 @@
1
+ status_OK == TRUE
@@ -0,0 +1,52 @@
1
+
2
+ require 'sbuilder'
3
+
4
+ require_relative "utils/string_inject"
5
+ require_relative "utils/logger"
6
+
7
+
8
+ require_relative "sbuilder/exception"
9
+
10
+ # mixers
11
+ require_relative "mixer/type_symbol"
12
+ require_relative "mixer/symbol_ref"
13
+ require_relative "mixer/scope"
14
+ require_relative "mixer/scoped"
15
+ require_relative "mixer/decl_ref"
16
+ require_relative "mixer/domain_ref"
17
+
18
+ # constants
19
+ require_relative "sbuilder/constants"
20
+
21
+ # solidity stuff
22
+ require_relative "sbuilder/compile"
23
+ require_relative "sbuilder/load"
24
+
25
+
26
+ require_relative "sbuilder/sexp_ast"
27
+ require_relative "sbuilder/sexp_utils"
28
+
29
+ # sex processors
30
+ require_relative "sbuilder/sexp_processor_ethereum"
31
+ require_relative "sbuilder/sexp_processor_need_to_canonize"
32
+ require_relative "sbuilder/sexp_processor_canonize"
33
+ require_relative "sbuilder/sexp_processor_symboltable1"
34
+ require_relative "sbuilder/sexp_processor_symboltable2"
35
+ require_relative "sbuilder/sexp_processor_dataflow"
36
+ require_relative "sbuilder/sexp_processor_api"
37
+ require_relative "sbuilder/sexp_processor_snippet"
38
+ require_relative "sbuilder/s"
39
+
40
+ # Code generation
41
+ require_relative "sbuilder/generate/tla_element_text"
42
+ require_relative "sbuilder/generate/tla_element_generator"
43
+ require_relative "sbuilder/generate/sexp_processor_tla"
44
+
45
+
46
+ # mustache
47
+ require_relative "sbuilder/mustache/renderer"
48
+ require_relative "sbuilder/render"
49
+
50
+ # plugin && main
51
+ require_relative "plugin/plugin"
52
+
@@ -0,0 +1,163 @@
1
+ require 'open3'
2
+ module Sbuilder
3
+ module Ethereum
4
+
5
+
6
+ ##
7
+ # Compile solidity source.
8
+ #
9
+ class Compile
10
+
11
+ PROGNAME = nil # progname for logger default class name
12
+ include MyLogger # mix logger
13
+
14
+ # @attr [String] solc_command
15
+ attr_writer :solc_command
16
+
17
+ # @attr [String] solc_flags
18
+ attr_reader :solc_flags
19
+
20
+ # @attr [String] output_directory, can be configured outside
21
+ attr_accessor :output_directory
22
+
23
+ # @attr [String] compiled_ast
24
+ attr_accessor :compiledAst
25
+
26
+ # ------------------------------------------------------------------
27
+ # @!group construct & configure
28
+
29
+ def initialize( options = {} )
30
+
31
+ @options = options
32
+ @logger = getLogger( nil, options )
33
+ @logger.info "#{__method__}: initalized"
34
+
35
+ initDefaults
36
+
37
+ end
38
+
39
+ # set configuration values
40
+ def initDefaults
41
+ @output_directory ||= "tmp/solidity"
42
+ @solc_flags ||= "--combined-json ast -o #{output_directory}"
43
+ end
44
+
45
+ # @return [String] path to solc executable
46
+ def solc_command
47
+ @solc_command ||= "#{Dir.pwd}/solc/solidity/build/solc/solc"
48
+ end
49
+
50
+ # @!endgroup
51
+
52
+
53
+ # ------------------------------------------------------------------
54
+ # @!group public services
55
+
56
+ ##
57
+ # Call +solc_command+ to compile solidity source in +sourcePath+
58
+ # to create abstract syntax tree file in +compiledAst+
59
+ #
60
+ # @param [String|String:Array] soliditySource to solidity file to compile
61
+ #
62
+ def compile( soliditySource )
63
+
64
+ self.compiledAst = nil
65
+
66
+ sourcePaths = soliditySource.is_a?( Array ) ? soliditySource : [soliditySource]
67
+
68
+ # Check sourcePath & compiler command
69
+ sourcePaths.each do |sourcePath|
70
+ @logger.info "#{__method__}: solc_command=#{solc_command}, solc_flags=#{solc_flags}, sourcePath=#{sourcePath}, pwd=#{Dir.pwd}"
71
+ raise SbuilderEtherumCompileException, "Solidity source file '#{sourcePath}': no such file" unless File.exists?( sourcePath )
72
+ end
73
+ raise SbuilderEtherumCompileException, "Solidity output directory '#{output_directory}': no such directory" unless Dir.exists?( output_directory )
74
+ raise SbuilderEtherumCompileException, "Solidity compiler '#{solc_command}': executabable not found" unless which( solc_command )
75
+
76
+
77
+ # ast named after first source file, must not exist
78
+ astPath = ast_path( sourcePaths.first )
79
+ File.delete( astPath ) if File.exists?( astPath )
80
+ raise SbuilderEtherumCompileException, "Solidity ast file '#{astPath}': could not remove" if File.exists?( astPath )
81
+
82
+
83
+ cmd = "#{solc_command} #{solc_flags} #{sourcePaths.join(' ')} > #{astPath}"
84
+ @logger.info "#{__method__}: cmd:#{cmd}"
85
+ out,err,exit_status = Open3.capture3( cmd )
86
+
87
+ @logger.info "#{__method__}: out=#{out}, err=#{err}, st=#{exit_status}"
88
+ raise SbuilderEtherumCompileException, <<-EOS if exit_status != 0
89
+ Error compiling #{sourcePaths.join(',')}
90
+
91
+ Compiler : #{solc_command}
92
+ Flags : #{solc_flags}
93
+
94
+ Exit status: #{exit_status}
95
+
96
+ Stderr: #{err}
97
+
98
+ Output: #{out}
99
+
100
+ EOS
101
+
102
+
103
+ # check that ast file was created
104
+ raise SbuilderEtherumCompileException, <<-EOS unless File.exists?( astPath )
105
+ Error compiling #{sourcePaths.join(',')}
106
+
107
+ Compiler command
108
+
109
+ #{cmd}
110
+
111
+ in cwd #{Dir.getwd}
112
+
113
+ failed to create solidity ast file '#{astPath}'
114
+
115
+ EOS
116
+
117
+
118
+ # return path to compiled ast file
119
+ self.compiledAst = astPath
120
+ @logger.info "#{__method__}, compiledAst=#{compiledAst}"
121
+ compiledAst
122
+ end
123
+
124
+ # @!endgroup
125
+
126
+
127
+ # ------------------------------------------------------------------
128
+ # @!group configuration
129
+
130
+ # @return [String] path to a file in output directory
131
+ def ast_path( sourcePath )
132
+ "#{output_directory}/#{ast_file(sourcePath)}"
133
+ end
134
+
135
+
136
+ # @return [String] filename for abstract syntax tree for
137
+ # solidity source in +sourcePath+
138
+ def ast_file( sourcePath )
139
+ "#{File.basename( sourcePath, File.extname(sourcePath) )}.sol_json.ast"
140
+ end
141
+
142
+ # @!endgroup
143
+
144
+ # ------------------------------------------------------------------
145
+ # @!group utilities
146
+
147
+ # @return [Boolean] true if +cmd+ points to executable or it is
148
+ # found in PATH
149
+ def which( cmd )
150
+ File.exists?( cmd ) && File.executable?( cmd ) ||
151
+ ENV['PATH'].split(':').select do |folder|
152
+ f = "#{folder}/#{cmd}"
153
+ File.exists?(f) && File.executable?(f)
154
+ end.any?
155
+ end
156
+
157
+ # @!endgroup
158
+
159
+
160
+ end
161
+
162
+ end
163
+ end