ciri 0.0.3 → 0.0.4
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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/Gemfile.lock +6 -6
- data/README.md +68 -48
- data/Rakefile +16 -11
- data/ciri-crypto/lib/ciri/crypto/signature.rb +7 -5
- data/ciri-rlp/ciri-rlp.gemspec +1 -1
- data/ciri-rlp/lib/ciri/rlp.rb +1 -1
- data/ciri-rlp/lib/ciri/rlp/decode.rb +23 -7
- data/ciri-rlp/lib/ciri/rlp/encode.rb +8 -2
- data/ciri-rlp/lib/ciri/rlp/serializable.rb +14 -4
- data/ciri-rlp/lib/ciri/rlp/version.rb +1 -1
- data/ciri-rlp/spec/ciri/fixture_spec.rb +2 -2
- data/ciri-utils/Gemfile.lock +1 -1
- data/ciri-utils/lib/ciri/utils/version.rb +1 -1
- data/ciri.gemspec +4 -4
- data/lib/ciri/chain/header.rb +13 -11
- data/lib/ciri/chain/header_chain.rb +1 -10
- data/lib/ciri/chain/transaction.rb +5 -23
- data/lib/ciri/db/account_db.rb +0 -4
- data/lib/ciri/db/backend/errors.rb +27 -0
- data/lib/ciri/db/backend/memory.rb +10 -12
- data/lib/ciri/db/backend/rocks.rb +13 -6
- data/lib/ciri/db/backend/rocks_db.rb +4 -0
- data/lib/ciri/evm.rb +6 -1
- data/lib/ciri/evm/execution_context.rb +6 -2
- data/lib/ciri/evm/instruction.rb +0 -1
- data/lib/ciri/evm/op.rb +11 -5
- data/lib/ciri/evm/op/errors.rb +37 -0
- data/lib/ciri/evm/state.rb +1 -1
- data/lib/ciri/evm/sub_state.rb +6 -6
- data/lib/ciri/evm/vm.rb +53 -33
- data/lib/ciri/forks.rb +4 -0
- data/lib/ciri/forks/base.rb +28 -0
- data/lib/ciri/forks/byzantium.rb +45 -11
- data/lib/ciri/forks/byzantium/opcodes.rb +37 -0
- data/lib/ciri/forks/constantinople.rb +29 -0
- data/lib/ciri/forks/frontier.rb +49 -29
- data/lib/ciri/forks/frontier/cost.rb +91 -95
- data/lib/ciri/forks/frontier/opcodes.rb +99 -0
- data/lib/ciri/forks/frontier/transaction.rb +62 -0
- data/lib/ciri/forks/homestead.rb +31 -7
- data/lib/ciri/forks/homestead/opcodes.rb +37 -0
- data/lib/ciri/forks/homestead/transaction.rb +43 -0
- data/lib/ciri/forks/spurious_dragon.rb +55 -0
- data/lib/ciri/forks/spurious_dragon/cost.rb +91 -0
- data/lib/ciri/forks/spurious_dragon/transaction.rb +44 -0
- data/lib/ciri/forks/tangerine_whistle.rb +37 -0
- data/lib/ciri/forks/tangerine_whistle/cost.rb +98 -0
- data/lib/ciri/rlp/decode.rb +4 -4
- data/lib/ciri/rlp/encode.rb +2 -2
- data/lib/ciri/version.rb +1 -1
- metadata +22 -10
- data/lib/ciri/forks/homestead/cost.rb +0 -195
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20618c56ec07fac482c96e6a4bd5cdb3f3bfb45402be5548e748994283246c99
|
4
|
+
data.tar.gz: d76e2848328eb6a42b4bd0705aaf20885a44cbb0b487b1d4a485fff92f0dd42a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 665f5f8f3d6437c24993c4e2f573b805886906a70f9a0fec5610eec0a5c870ce5d8d8b72558212b5600ba3c9f23f9a29287d2d53bdc85c91623caf8cc487dbc5
|
7
|
+
data.tar.gz: b16a58be1b92f544c2670a2c6956b2943d14f5f5cc1ffc05a3be3f148578049754a2bfc146372f20e493fb127bda8668c2e2174d304a82bb42cd27d26dc7b1e4
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ciri (0.0.
|
4
|
+
ciri (0.0.4)
|
5
5
|
bitcoin-secp256k1 (~> 0.4.0)
|
6
6
|
ciri-crypto (~> 0.1.1)
|
7
|
-
ciri-rlp (~> 0.
|
8
|
-
ciri-utils (~> 0.2.
|
7
|
+
ciri-rlp (~> 0.2.1)
|
8
|
+
ciri-utils (~> 0.2.1)
|
9
9
|
concurrent-ruby (~> 1.0.5)
|
10
10
|
ffi (~> 1.9.23)
|
11
11
|
lru_redux (~> 1.1.0)
|
@@ -13,9 +13,9 @@ PATH
|
|
13
13
|
ciri-crypto (0.1.1)
|
14
14
|
bitcoin-secp256k1 (~> 0.4.0)
|
15
15
|
ciri-utils (~> 0.2.0)
|
16
|
-
ciri-rlp (0.
|
17
|
-
ciri-utils (~> 0.2.
|
18
|
-
ciri-utils (0.2.
|
16
|
+
ciri-rlp (0.2.1)
|
17
|
+
ciri-utils (~> 0.2.1)
|
18
|
+
ciri-utils (0.2.1)
|
19
19
|
digest-sha3 (~> 1.1.0)
|
20
20
|
|
21
21
|
GEM
|
data/README.md
CHANGED
@@ -3,32 +3,79 @@ Ciri
|
|
3
3
|
[](https://travis-ci.org/ciri-ethereum/ciri)
|
4
4
|
[](https://gitter.im/ciri-ethereum/Lobby)
|
5
5
|
|
6
|
-
Ciri
|
6
|
+
Ciri is an ongoing Ethereum implementation.
|
7
7
|
|
8
|
-
It aims to be a feature complete
|
9
|
-
As you see it'
|
8
|
+
It aims to be a feature complete Ethereum implementation and expects to achieve both research-friendly and high-performance.
|
9
|
+
As you see, it's still under development.
|
10
10
|
|
11
|
-
|
11
|
+
See [How to learn Ethereum and contribute to Ciri](https://github.com/ciri-ethereum/ciri/wiki#how-to-learn-ethereum-and-contribute-to-ciri).
|
12
12
|
|
13
13
|
See [projects](https://github.com/ciri-ethereum/ciri/projects) and [milestones](https://github.com/ciri-ethereum/ciri/milestones) for current development status.
|
14
14
|
|
15
15
|
Roadmap
|
16
16
|
---------------
|
17
17
|
|
18
|
-
See [
|
19
|
-
|
20
|
-
Documentation
|
21
|
-
---------------
|
22
|
-
|
23
|
-
[YARD documentation](https://www.rubydoc.info/github/ciri-ethereum/ciri/master)
|
18
|
+
See [Roadmap](https://github.com/ciri-ethereum/ciri/wiki) on Wiki
|
24
19
|
|
25
20
|
Development
|
26
21
|
---------------
|
27
22
|
|
28
23
|
Ciri depends on [rocksdb](https://github.com/facebook/rocksdb), [secp256k1](https://github.com/bitcoin-core/secp256k1), [ethash](https://github.com/ethereum/ethash) and [snappy](https://github.com/google/snappy).
|
29
24
|
|
30
|
-
It's recommendation to [setup with docker](#setup-with-docker), it will save lots of time.
|
25
|
+
It's a recommendation to [setup with docker](#setup-with-docker), it will help to save lots of time.
|
26
|
+
|
27
|
+
### Setup with docker
|
28
|
+
|
29
|
+
Use docker command to pull image:
|
30
|
+
|
31
|
+
``` bash
|
32
|
+
docker pull ciriethereum/ciri
|
33
|
+
```
|
34
|
+
|
35
|
+
Or you can use our prepared rake tasks if you're not familiar with docker:
|
36
|
+
|
37
|
+
clone repo and submodules
|
38
|
+
|
39
|
+
``` bash
|
40
|
+
git clone --recursive https://github.com/ciri-ethereum/ciri.git
|
41
|
+
cd ciri
|
42
|
+
```
|
43
|
+
|
44
|
+
make sure we have installed docker, ruby and rake
|
45
|
+
``` bash
|
46
|
+
# make sure we have installed docker, ruby and rake
|
47
|
+
docker -v
|
48
|
+
gem install rake
|
49
|
+
```
|
50
|
+
|
51
|
+
#### Pull docker image
|
52
|
+
|
53
|
+
``` bash
|
54
|
+
# pull Ciri docker image
|
55
|
+
rake docker:pull
|
56
|
+
```
|
57
|
+
|
58
|
+
#### Build docker image
|
59
|
+
(it will take a few minutes)
|
60
|
+
``` bash
|
61
|
+
# build Ciri docker image
|
62
|
+
rake docker:build
|
63
|
+
```
|
64
|
+
|
65
|
+
#### Run tests in docker
|
66
|
+
``` bash
|
67
|
+
# run tests
|
68
|
+
rake docker:quick
|
69
|
+
```
|
70
|
+
|
71
|
+
#### Other usages
|
72
|
+
``` bash
|
73
|
+
# open a shell for developing
|
74
|
+
rake docker:shell
|
31
75
|
|
76
|
+
# type 'rake -T' see other supported tasks
|
77
|
+
rake -T
|
78
|
+
```
|
32
79
|
|
33
80
|
### Manually Setup
|
34
81
|
|
@@ -40,7 +87,7 @@ git clone --recursive https://github.com/ciri-ethereum/ciri.git
|
|
40
87
|
|
41
88
|
#### Install dependencies
|
42
89
|
|
43
|
-
On mac you can install `rocksdb` and `snappy` with homebrew
|
90
|
+
On a mac you can install `rocksdb` and `snappy` with homebrew
|
44
91
|
|
45
92
|
``` bash
|
46
93
|
brew install rocksdb snappy
|
@@ -58,7 +105,7 @@ secp256k1
|
|
58
105
|
cd secp256k1 && ./autogen.sh && ./configure --enable-module-recovery --enable-experimental --enable-module-ecdh && make && make install
|
59
106
|
```
|
60
107
|
|
61
|
-
For linux
|
108
|
+
For linux users, remember to check [Dockerfile](/docker) instructions for hint.
|
62
109
|
|
63
110
|
then run:
|
64
111
|
``` bash
|
@@ -67,49 +114,22 @@ bundle install
|
|
67
114
|
|
68
115
|
run tests:
|
69
116
|
``` bash
|
70
|
-
RUBY_THREAD_VM_STACK_SIZE=52428800 bundle exec rake
|
117
|
+
RUBY_THREAD_VM_STACK_SIZE=52428800 bundle exec rake quick
|
71
118
|
```
|
72
119
|
|
120
|
+
Why Ruby?
|
121
|
+
---------------
|
73
122
|
|
74
|
-
|
123
|
+
> Because Ruby has built-in block support!
|
75
124
|
|
76
|
-
|
125
|
+
Seriously,
|
77
126
|
|
78
|
-
|
79
|
-
``` bash
|
80
|
-
# make sure we have installed docker, ruby and rake
|
81
|
-
docker -v
|
82
|
-
gem install rake
|
83
|
-
```
|
127
|
+
Ruby is a scripting language which makes it easy to write prototype or research code (like the official python Ethereum implementation intended).
|
84
128
|
|
85
|
-
|
86
|
-
pull latest released Ciri docker image
|
87
|
-
``` bash
|
88
|
-
# pull Ciri docker image
|
89
|
-
rake docker:pull
|
90
|
-
```
|
91
|
-
|
92
|
-
#### Build docker image
|
93
|
-
build local docker image (it will take few minutes)
|
94
|
-
``` bash
|
95
|
-
# build Ciri docker image
|
96
|
-
rake docker:build
|
97
|
-
```
|
129
|
+
According to the several performance research projects in Ruby community (JIT, JRuby, TruffleRuby), we are highly looking forward to seeing improvement of this language performance in the future.
|
98
130
|
|
99
|
-
|
100
|
-
``` bash
|
101
|
-
# run tests
|
102
|
-
rake docker:test
|
103
|
-
```
|
131
|
+
Due to Ruby, we could expect to achieve both research-friendly and high-performance in our implementation.
|
104
132
|
|
105
|
-
#### Other usage
|
106
|
-
``` bash
|
107
|
-
# open a shell for develop
|
108
|
-
rake docker:shell
|
109
|
-
|
110
|
-
# cool, type 'rake -T' see other supported tasks
|
111
|
-
rake -T
|
112
|
-
```
|
113
133
|
|
114
134
|
Contributors
|
115
135
|
---------------
|
data/Rakefile
CHANGED
@@ -14,8 +14,8 @@ end
|
|
14
14
|
|
15
15
|
SUB_COMPONENTS = %w{ciri-utils ciri-rlp ciri-crypto}
|
16
16
|
|
17
|
-
desc 'run
|
18
|
-
task :
|
17
|
+
desc 'run quick spec'
|
18
|
+
task :quick do
|
19
19
|
exit(1) unless check_env
|
20
20
|
run("rspec -t ~slow_tests")
|
21
21
|
SUB_COMPONENTS.each do |dir|
|
@@ -23,8 +23,8 @@ task :test do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
desc 'run all
|
27
|
-
task :"
|
26
|
+
desc 'run all specs, include extreme slow tests'
|
27
|
+
task :"spec:all" do
|
28
28
|
exit(1) unless check_env
|
29
29
|
run("rspec")
|
30
30
|
SUB_COMPONENTS.each do |dir|
|
@@ -33,7 +33,7 @@ task :"test:all" do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
namespace :docker do
|
36
|
-
base_image = 'ciriethereum/
|
36
|
+
base_image = 'ciriethereum/ciri'
|
37
37
|
|
38
38
|
desc 'pull docker image'
|
39
39
|
task :pull do
|
@@ -46,6 +46,11 @@ namespace :docker do
|
|
46
46
|
run("docker build . -f docker/Dockerfile -t #{base_image}:latest")
|
47
47
|
end
|
48
48
|
|
49
|
+
desc 'push docker image'
|
50
|
+
task :push do
|
51
|
+
run("docker push #{base_image}:latest")
|
52
|
+
end
|
53
|
+
|
49
54
|
desc 'open Ciri develop container shell'
|
50
55
|
task :shell do
|
51
56
|
container_name = 'ciri-develop'
|
@@ -57,14 +62,14 @@ namespace :docker do
|
|
57
62
|
end
|
58
63
|
end
|
59
64
|
|
60
|
-
desc 'run
|
61
|
-
task :
|
62
|
-
run("docker run -v `pwd`:/app --rm #{base_image}:latest rake
|
65
|
+
desc 'run quick specs in docker'
|
66
|
+
task :quick do
|
67
|
+
run("docker run -v `pwd`:/app --rm #{base_image}:latest rake quick")
|
63
68
|
end
|
64
69
|
|
65
|
-
desc 'run all
|
66
|
-
task :"
|
67
|
-
run("docker run -v `pwd`:/app --rm #{base_image}:latest rake
|
70
|
+
desc 'run all specs(include slow tests) in docker'
|
71
|
+
task :"spec:all" do
|
72
|
+
run("docker run -v `pwd`:/app --rm #{base_image}:latest rake spec:all")
|
68
73
|
end
|
69
74
|
|
70
75
|
private
|
@@ -50,20 +50,22 @@ module Ciri
|
|
50
50
|
|
51
51
|
def signature
|
52
52
|
@signature ||= Utils.big_endian_encode(@r, "\x00".b, size: 32) +
|
53
|
-
|
54
|
-
|
53
|
+
Utils.big_endian_encode(@s, "\x00".b, size: 32) +
|
54
|
+
Utils.big_endian_encode(@v, "\x00".b)
|
55
55
|
end
|
56
56
|
|
57
57
|
alias to_s signature
|
58
58
|
|
59
59
|
def valid?
|
60
60
|
v <= 1 &&
|
61
|
-
|
62
|
-
|
61
|
+
r < SECP256K1N && r >= 1 &&
|
62
|
+
s < SECP256K1N && s >= 1
|
63
63
|
end
|
64
64
|
|
65
|
+
# high s value is invalid after Homestead fork
|
66
|
+
# see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.md#specification
|
65
67
|
def low_s?
|
66
|
-
s
|
68
|
+
s <= (SECP256K1N / 2)
|
67
69
|
end
|
68
70
|
end
|
69
71
|
|
data/ciri-rlp/ciri-rlp.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.add_dependency "ciri-utils", "~> 0.2.
|
24
|
+
spec.add_dependency "ciri-utils", "~> 0.2.1"
|
25
25
|
spec.add_development_dependency "bundler", "~> 1.16"
|
26
26
|
spec.add_development_dependency "rake", "~> 12.0"
|
27
27
|
spec.add_development_dependency "rspec", "~> 3.0"
|
data/ciri-rlp/lib/ciri/rlp.rb
CHANGED
@@ -44,7 +44,7 @@ module Ciri
|
|
44
44
|
if type == Integer
|
45
45
|
item = s.read(1)
|
46
46
|
if item.nil?
|
47
|
-
raise
|
47
|
+
raise InvalidError.new "invalid bool value nil"
|
48
48
|
elsif item == "\x80".b || item.empty?
|
49
49
|
0
|
50
50
|
elsif item.ord < 0x80
|
@@ -60,7 +60,7 @@ module Ciri
|
|
60
60
|
elsif item == Bool::ENCODED_FALSE
|
61
61
|
false
|
62
62
|
else
|
63
|
-
raise
|
63
|
+
raise InvalidError.new "invalid bool value #{item}"
|
64
64
|
end
|
65
65
|
elsif type.is_a?(Class) && type.respond_to?(:rlp_decode)
|
66
66
|
type.rlp_decode(s)
|
@@ -73,10 +73,18 @@ module Ciri
|
|
73
73
|
i += 1
|
74
74
|
end
|
75
75
|
end
|
76
|
+
elsif type == RawString
|
77
|
+
str = decode_stream(s)
|
78
|
+
raise RLP::InvalidError.new "decode #{str.class} from RawString" unless str.is_a?(String)
|
79
|
+
str
|
80
|
+
elsif type == RawList
|
81
|
+
list = decode_stream(s)
|
82
|
+
raise RLP::InvalidError.new "decode #{list.class} from RawList" unless list.is_a?(Array)
|
83
|
+
list
|
76
84
|
elsif type == Raw
|
77
85
|
decode_stream(s)
|
78
86
|
else
|
79
|
-
raise RLP::
|
87
|
+
raise RLP::InvalidError.new "unknown type #{type}"
|
80
88
|
end
|
81
89
|
rescue
|
82
90
|
STDERR.puts "when decoding #{s} into #{type}"
|
@@ -89,7 +97,6 @@ module Ciri
|
|
89
97
|
s = StringIO.new(s) if s.is_a?(String)
|
90
98
|
c = first_char || s.read(1)
|
91
99
|
list = []
|
92
|
-
|
93
100
|
sub_s = case c.ord
|
94
101
|
when 0xc0..0xf7
|
95
102
|
length = c.ord - 0xc0
|
@@ -97,11 +104,13 @@ module Ciri
|
|
97
104
|
when 0xf8..0xff
|
98
105
|
length_binary = s.read(c.ord - 0xf7)
|
99
106
|
length = int_from_binary(length_binary)
|
100
|
-
s
|
107
|
+
check_range_and_read(s, length)
|
101
108
|
else
|
102
|
-
raise
|
109
|
+
raise InvalidError.new("invalid char #{c}")
|
103
110
|
end
|
104
111
|
|
112
|
+
raise InvalidError.new("stream EOF when encode_list") unless sub_s
|
113
|
+
|
105
114
|
decoder.call(list, StringIO.new(sub_s))
|
106
115
|
list
|
107
116
|
end
|
@@ -110,6 +119,7 @@ module Ciri
|
|
110
119
|
|
111
120
|
def decode_stream(s)
|
112
121
|
c = s.read(1)
|
122
|
+
raise InvalidError.new("read none char from stream") unless c
|
113
123
|
case c.ord
|
114
124
|
when 0x00..0x7f
|
115
125
|
c
|
@@ -119,7 +129,7 @@ module Ciri
|
|
119
129
|
when 0xb8..0xbf
|
120
130
|
length_binary = s.read(c.ord - 0xb7)
|
121
131
|
length = int_from_binary(length_binary)
|
122
|
-
s
|
132
|
+
check_range_and_read(s, length)
|
123
133
|
else
|
124
134
|
decode_list(s, c) do |list, s2|
|
125
135
|
until s2.eof?
|
@@ -129,6 +139,12 @@ module Ciri
|
|
129
139
|
end
|
130
140
|
end
|
131
141
|
|
142
|
+
def check_range_and_read(s, length)
|
143
|
+
s.read(length)
|
144
|
+
rescue RangeError
|
145
|
+
raise InvalidError.new("length too long: #{length}")
|
146
|
+
end
|
147
|
+
|
132
148
|
def int_from_binary(input)
|
133
149
|
Ciri::Utils.big_endian_decode(input)
|
134
150
|
end
|
@@ -70,12 +70,18 @@ module Ciri
|
|
70
70
|
if type.size == 1 # array type
|
71
71
|
encode_list(item) {|i| encode_with_type(i, type[0])}
|
72
72
|
else # unknown
|
73
|
-
raise RLP::
|
73
|
+
raise RLP::InvalidError.new "type size should be 1, got #{type}"
|
74
74
|
end
|
75
75
|
elsif type == Raw
|
76
76
|
encode_raw(item)
|
77
|
+
elsif type == RawString
|
78
|
+
raise RLP::InvalidError.new "expect String, got #{item.class}" unless item.is_a?(String)
|
79
|
+
encode_raw(item)
|
80
|
+
elsif type == RawList
|
81
|
+
raise RLP::InvalidError.new "expect Array, got #{item.class}" unless item.is_a?(Array)
|
82
|
+
encode_raw(item)
|
77
83
|
else
|
78
|
-
raise RLP::
|
84
|
+
raise RLP::InvalidError.new "unknown type #{type}"
|
79
85
|
end
|
80
86
|
rescue
|
81
87
|
STDERR.puts "when encoding #{Utils.to_hex item.to_s} into #{type}"
|
@@ -30,6 +30,12 @@ module Ciri
|
|
30
30
|
class Raw
|
31
31
|
end
|
32
32
|
|
33
|
+
class RawString
|
34
|
+
end
|
35
|
+
|
36
|
+
class RawList
|
37
|
+
end
|
38
|
+
|
33
39
|
# Serializable module allow ruby objects serialize/deserialize to or from RLP encoding.
|
34
40
|
# See Ciri::RLP::Serializable::TYPES for supported type.
|
35
41
|
#
|
@@ -69,7 +75,7 @@ module Ciri
|
|
69
75
|
#
|
70
76
|
module Serializable
|
71
77
|
# nil represent RLP raw value(string or array of string)
|
72
|
-
TYPES = [Raw, Integer, Bool].map {|key| [key, true]}.to_h.freeze
|
78
|
+
TYPES = [Raw, RawString, RawList, Integer, Bool].map {|key| [key, true]}.to_h.freeze
|
73
79
|
|
74
80
|
# Schema specific columns types of classes, normally you should not use Serializable::Schema directly
|
75
81
|
#
|
@@ -176,9 +182,13 @@ module Ciri
|
|
176
182
|
end
|
177
183
|
|
178
184
|
def schema(data_schema = nil)
|
179
|
-
|
180
|
-
|
181
|
-
|
185
|
+
if data_schema
|
186
|
+
@data_schema = Schema.new(data_schema).tap do |schema|
|
187
|
+
# define attributes methods
|
188
|
+
define_attributes(schema)
|
189
|
+
end
|
190
|
+
else
|
191
|
+
@data_schema ||= superclass.schema
|
182
192
|
end
|
183
193
|
end
|
184
194
|
|